Подтвердить что ты не робот

GHCi игнорирует подпись типа

Prelude> let myprint = putStrLn . show
Prelude> :t myprint
myprint :: () -> IO ()

Хорошо, здесь нет ничего необычного. Просто правила GHCi по умолчанию, я думаю...

Prelude> let myprint = (putStrLn . show) :: Show x => x -> IO ()
Prelude> :t myprint
myprint :: () -> IO ()

Какое колдовство это? Вы просто игнорируете мое объявление типа? О_О

Есть ли способ убедить GHCi делать то, что я на самом деле намеревался сделать?

4b9b3361

Ответ 1

Мы можем сделать следующее с ограничением мономорфизма на:

>let myprint :: Show x => x -> IO (); myprint = putStrLn . show
>:t myprint
myprint :: Show x => x -> IO ()

Это не то же самое, что let myprint = putStrLn . show :: Show x => x -> IO (). В первом случае мы имеем привязку с сигнатурой типа, в последнем случае мы имеем привязку let с аннотацией типа внутри правой стороны. Мономорфизм проверяет сигнатуры верхнего уровня, но не локальные аннотации.

Ответ 2

Добавление аннотации типа к выражению, как в

e :: type

заставляет компилятор проверить, что e имеет type, а также использовать type для создания экземпляров переменных экземпляра и выбора экземпляра. Однако, если type является полиморфным, он все равно может быть создан позже. Рассмотрим, например,

(id :: a -> a) "hello"

Выше, a будет создаваться на String, несмотря на мою аннотацию. Далее,

foo :: Int -> Int
foo = (id :: a -> a)

сделает a для последующего экземпляра Int. Вышеупомянутая аннотация id не дает никакой информации для GHC: она уже знает, что id имеет этот тип. Мы могли бы удалить его, не затрагивая проверку типов вообще. То есть выражения id и id :: a->a не только динамически эквивалентны, но и статически таковы.

Аналогично, выражения

putStrLn . show

и

(putStrLn . show) :: Show x => x -> IO ()

являются статически эквивалентными: мы просто комментируем код с типом GHC. Другими словами, мы не предоставляем какую-либо информацию GHC, которую она еще не знает.

После проверки типа аннотации GHC может затем создать экземпляр x далее. Ограничение мономорфизма делает это в вашем примере. Чтобы этого избежать, используйте аннотацию для привязки, которую вы вводите, а не выражение:

myprint :: Show x => x -> IO ()
myprint = (putStrLn . show)