Во-первых, давайте уточним одну вещь.Что произойдет, если мы определим функцию в GHCi, а не запрашиваем тип?
> let x = map length . sum :: (Num [[a]]) => [[[a]]] -> [Int]
<interactive>:0:9:
Non type-variable argument in the constraint: Num [[a]]
(Use -XFlexibleContexts to permit this)
In an expression type signature: Num [[a]] => [[[a]]] -> [Int]
И так далее.Другими словами, то же самое.Что если мы позволим GHCi определить тип определения?
> let x = map length . sum
<interactive>:0:22:
No instance for (Num [[a0]])
arising from a use of `sum'
Possible fix: add an instance declaration for (Num [[a0]])
In the second argument of `(.)', namely `sum'
In the expression: map length . sum
Это примерно та же ошибка, которая возникает при загрузке файла, содержащего определение, без сигнатуры типа.
Каков результатвсего этого?Хорошо, подумайте о том, что сообщает , какое расширение необходимо.GHC способен распознавать, что тип означает , даже если он отклоняет тип по умолчанию.Я вряд ли ожидал, что GHC будет использовать совершенно другую программу проверки типов в зависимости от комбинации используемых расширений, поэтому, кажется, легко сделать вывод, что тип-нарушитель отклоняется ни по какой причине, кроме того, что отключено соответствующее расширение.
Команда :t
в GHCi не является частью процесса компиляции - это горячая линия для системы проверки типов и логического вывода, позволяющая задать тип гипотетического кода.У него нет очевидной причины произвольно ограничивать себя на основе расширений, когда более общий тип все еще может быть информативным, по той же причине, по которой в приведенных выше сообщениях об ошибках сообщается use -XFlexibleContexts to permit this
, а не просто syntax error in type constraint
.
Возможно, что еще более интересно, есть также случаи, когда выводимый тип будет с радостью принят компилятором, но выводимый тип не может быть записан явно по одной из нескольких причин.
Например, отключение ограничения мономорфизма позволит вашему примеру выводить его тип (в соответствии с тем, что говорит :t
), несмотря на то, что этот тип требует расширения для записи вручную.
Другим примером являются определения в where
предложение определения функции, которое использует полиморфные аргументы родительской функции.Их собственные типы не являются полиморфными, поскольку диктуются аргументами, полученными во внешней области видимости, однако переменные типа в сигнатуре родительской функции не входят в область действия для предложения where
.Также могут быть и другие примеры.
variables Переменные типа из подписи родителя могут быть введены в область видимости с расширением ScopedTypeVariables
и явным forall
, если это необходимо.