Я пытаюсь понять, как ограничения типов работают с псевдонимами типов. Во-первых, предположим, что у меня есть псевдоним следующего типа:
type NumList a = Num a => [a]
И у меня есть следующая функция:
addFirst :: a -> NumList a -> NumList
addFirst x (y:_) = x + y
Эта функция завершается со следующей ошибкой:
Type.hs:9:13: error:
• No instance for (Num a) arising from a pattern
Possible fix:
add (Num a) to the context of
the type signature for:
addFirst :: a -> NumList a -> a
• In the pattern: y : _
In an equation for ‘addFirst’: ad
Что очевидно. Эта проблема уже описана здесь:
Понимание псевдонима типа ранга 2 с ограничением класса а>
И я понимаю, почему нам нужно {-# LANGUAGE RankNTypes #-}
для работы таких псевдонимов типов и почему предыдущий пример не работает. Но я не понимаю, почему следующий пример компилируется нормально (на ghc 8):
prepend :: a -> NumList a -> NumList a
prepend = (:)
Конечно, в ghci
произойдет сбой, если я попытаюсь передать неправильное значение:
λ: prepend 1 []
[1]
λ: prepend "xx" []
<interactive>:3:1: error:
• No instance for (Num [Char]) arising from a use of ‘prepend’
• When instantiating ‘it’, initially inferred to have
this overly-general type:
NumList [Char]
NB: This instantiation can be caused by the monomorphism restriction.
Похоже, что проверка типа задерживается во время выполнения :(
Более того, какой-то простой и вроде бы одинаковый кусок кода не компилируется:
first :: NumList a -> a
first = head
И выдает следующую ошибку:
Type.hs:12:9: error:
• No instance for (Num a)
Possible fix:
add (Num a) to the context of
the type signature for:
first :: NumList a -> a
• In the expression: head
In an equation for ‘first’: first = head
Может кто-нибудь объяснить, что здесь происходит? Я ожидаю некоторой согласованности в том, проверяет ли тип функции или нет.
Num a => a
как о функцииNumDict a -> a
, и все должно быть ясно. - person Reid Barton   schedule 26.10.2016prepend
работает, а другие функции - нет (в Короче говоря, компилятор может переместить ограничение туда, где вы хотите, только если у вас есть синоним в самой правой позиции подписи). Кстати, обратите внимание, что в ваших примерах использованияprepend
нет ничего странного или запоздалого — она делает именно то, что вы ожидаете от функцииNum a => a -> [a] -> [a]
. - person duplode   schedule 26.10.2016foo :: forall a . a -> (forall b . b)
это то же самое, что иfoo :: forall a b . a -> b
. Но теперь я вижу, что такие правила также распространяются на ограничения, если вы представляете их в виде словарей. Теперь это выглядит довольно элегантно :) - person Shersh   schedule 26.10.2016