Я озадачен тем, как компилятор haskell иногда запрашивает типы, которые меньше полиморфный, чем то, что я ожидал бы, например, при использовании точечных определений.
Похоже, проблема заключается в "ограничении мономорфизма", который по умолчанию включен более старые версии компилятора.
Рассмотрим следующую программу haskell:
{-# LANGUAGE MonomorphismRestriction #-}
import Data.List(sortBy)
plus = (+)
plus' x = (+ x)
sort = sortBy compare
main = do
print $ plus' 1.0 2.0
print $ plus 1.0 2.0
print $ sort [3, 1, 2]
Если я скомпилирую это с помощью ghc
, я не получаю erros, а вывод исполняемого файла:
3.0
3.0
[1,2,3]
Если я изменил тело main
на:
main = do
print $ plus' 1.0 2.0
print $ plus (1 :: Int) 2
print $ sort [3, 1, 2]
Я не получаю ошибок времени компиляции, и результат становится:
3.0
3
[1,2,3]
как ожидалось. Однако, если я попытаюсь изменить его на:
main = do
print $ plus' 1.0 2.0
print $ plus (1 :: Int) 2
print $ plus 1.0 2.0
print $ sort [3, 1, 2]
Я получаю ошибку типа:
test.hs:13:16:
No instance for (Fractional Int) arising from the literal ‘1.0’
In the first argument of ‘plus’, namely ‘1.0’
In the second argument of ‘($)’, namely ‘plus 1.0 2.0’
In a stmt of a 'do' block: print $ plus 1.0 2.0
То же самое происходит при попытке дважды вызвать sort
с разными типами:
main = do
print $ plus' 1.0 2.0
print $ plus 1.0 2.0
print $ sort [3, 1, 2]
print $ sort "cba"
выдает следующую ошибку:
test.hs:14:17:
No instance for (Num Char) arising from the literal ‘3’
In the expression: 3
In the first argument of ‘sort’, namely ‘[3, 1, 2]’
In the second argument of ‘($)’, namely ‘sort [3, 1, 2]’
- Почему
ghc
вдруг думает, чтоplus
не является полиморфным и требует аргументInt
? Единственная ссылка наInt
находится в приложенииplus
, как это может иметь значение когда определение явно полиморфно? - Почему
ghc
вдруг думает, чтоsort
требуется экземплярNum Char
?
Более того, если я попытаюсь поместить определения функций в их собственный модуль, как в:
{-# LANGUAGE MonomorphismRestriction #-}
module TestMono where
import Data.List(sortBy)
plus = (+)
plus' x = (+ x)
sort = sortBy compare
При компиляции я получаю следующую ошибку:
TestMono.hs:10:15:
No instance for (Ord a0) arising from a use of ‘compare’
The type variable ‘a0’ is ambiguous
Relevant bindings include
sort :: [a0] -> [a0] (bound at TestMono.hs:10:1)
Note: there are several potential instances:
instance Integral a => Ord (GHC.Real.Ratio a)
-- Defined in ‘GHC.Real’
instance Ord () -- Defined in ‘GHC.Classes’
instance (Ord a, Ord b) => Ord (a, b) -- Defined in ‘GHC.Classes’
...plus 23 others
In the first argument of ‘sortBy’, namely ‘compare’
In the expression: sortBy compare
In an equation for ‘sort’: sort = sortBy compare
- Почему
ghc
не может использовать полиморфный типOrd a => [a] -> [a]
дляsort
? - И почему
ghc
обрабатываетplus
иplus'
по-другому?plus
должен иметь полиморфный типNum a => a -> a -> a
, и я действительно не вижу, как это отличается от типаsort
, но толькоsort
вызывает ошибку.
Последняя вещь: если я комментирую определение sort
, файл компилируется. Однако
если я попытаюсь загрузить его в ghci
и проверить типы, которые я получаю:
*TestMono> :t plus
plus :: Integer -> Integer -> Integer
*TestMono> :t plus'
plus' :: Num a => a -> a -> a
Почему тип plus
не является полиморфным?
Это канонический вопрос об ограничении мономорфизма в Haskell как обсуждалось в мета-вопросе.