Что такое AllowAmbiguousTypes и почему это необходимо в этом примере "forall"?

код

{-# LANGUAGE ScopedTypeVariables, TypeApplications #-}

-- I know this particular example is silly.
-- But that's not the point here.
g :: forall a . RealFloat a => Bool
g = True

main :: IO ()
main = print (g @Double)

не удается скомпилировать на GHC 8.0 с ошибкой

• Could not deduce (RealFloat a0)
      from the context: RealFloat a
        bound by the type signature for:
                   g :: RealFloat a => Bool
        at app/Main.hs:3:6-35
      The type variable ‘a0’ is ambiguous
    • In the ambiguity check for ‘g’
      To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
      In the type signature:
        g :: forall a. RealFloat a => Bool

чтобы добавлять AllowAmbiguousTypes сделает компиляцию кода.

вот мои вопросы:

  • что именно AllowAmbiguousTypes?
  • зачем нужно, чтобы этот конкретный код работал?
  • боюсь, что добавление AllowAmbiguousTypes дает мне больше, чем я действительно хочу в этот конкретный код. Звучит пугающе. Похоже, это сделает Хаскелла тип системы менее безопасен, возможно, в других областях, которые не имеют ничего общего с этим конкретным кодом. Эти опасения беспочвенны?
  • есть ли альтернативы? В этом случае кажется, что Haskell вставляет a0 введите переменную, которую я никогда не просил. Нет ли расширения, чтобы сказать Haskell не создавать эти посторонние переменные типа - и использовать только те, которые я явно сказал ему добавить с моим собственным explicit forall a?
  • добавил один вопрос из-за user2407038комментарий: Вы бы сказали, что AllowAmbiguousTypes является неправильным? Было бы лучше назвать его AllowUnusedTypeVariables?

1 ответов


что именно AllowAmbiguousTypes?

С последние GHC docs, "типа ty неоднозначно, если и только если ((undefined :: ty) :: ty) не typecheck". Расширение AllowAmbiguousTypes просто отключает эту проверку - это не позволит плохо типизированным программам.

зачем нужно, чтобы этот конкретный код работал?

для того, чтобы проверить это RealFloat a удовлетворен, когда g используется, GHC должен знать что?!--7--> есть. У вас нет пути (в vanilla Haskell1) говорить GHC что a должен быть с a больше нигде не встречается в типе g. Никакое количество аннотаций не позволит вам использовать g без получения неоднозначной ошибки переменной типа.

однако, если вы не использовать g в любом месте, вы можете получить код для компиляции, поворачивая на AllowAmbiguousTypes.

боюсь, что добавление AllowAmbiguousTypes это дает мне больше чем я действительно хочу в этом конкретном коде. Звучит пугающе. Похоже, это сделает систему типов Haskell менее безопасной, возможно, в других областях, которые не имеют ничего общего с этим конкретным кодом. Эти опасения беспочвенны?

Да, они: проверка неоднозначности позволяет вам поймать определения, которые не могут (в vanilla Haskell, у которого нет TypeApplications1) используется без возникновения неоднозначной ошибки переменной типа. Отключение этой проверки означает, что вы будет отображаться неоднозначное сообщение переменной типа при использовании выражения (или функции) вместо его сайта определения.

есть ли альтернативы? В этом случае кажется, что Haskell вставляет a0 введите переменную, которую я никогда не просил. Нет ли расширения, чтобы сказать Haskell не создавать эти посторонние переменные типа - и использовать только те, которые я явно сказал ему добавить с моим собственным explicit forall a?

на a0 is исходя из проверки двусмысленности, которую я упомянул в начале этого ответа. GHC просто использует имя a0 чтобы было ясно, что он отличается от a. Проверка неоднозначности в основном просто пытается typecheck

((undefined :: forall a. RealFloat a => Bool) :: forall a0. RealFloat a0 => Bool)

AllowAmbiguousTypes удаляет эту проверку. Я не думаю, что есть расширение, которое отключает проверки двусмысленности только на сигнатурах типа с явным foralls (хотя это может быть аккуратно и полезно!).

вы бы сказали, что AllowAmbiguousTypes это неправильно? Было бы лучше назвать его AllowUnusedTypeVariables?

называть вещи трудно. :)

текущее имя ссылается на тип ошибок, которые вы получаете без включенного расширения, поэтому это не плохое имя. Думаю, это вопрос мнения. (Многие люди также хотят Monad называлась что-то вроде FlatMapAble.)


1 до TypeApplications (что является относительно новым расширением от GHC 8.0), действительно не было никакого способа использование выражений, которые вызвали проверку неоднозначности без получения ошибки переменной неоднозначного типа, поэтому AllowAmbiguousTypes было намного менее полезно.