Haskell: Почему нет несоответствия типа (и почему это компилируется)?
Я был так сонлив, что написал следующий код (измененный, чтобы просто показать путаницу):
fac s = take 10 [s, s `mod` 1 ..]
maxFactor x = if (s == [])
then x
else head <-- this should be 'head x' instead of just 'head'
where s = fac x
Однако эта загрузка в ghci (и компиляция) просто прекрасна. Когда я выполнил maxFactor 1
, он жалуется (конечно):
<interactive>:0:1:
No instance for (Integral ([a0] -> a0))
arising from a use of `maxFactor'
Possible fix:
add an instance declaration for (Integral ([a0] -> a0))
In the expression: maxFactor 1
In an equation for `it': it = maxFactor 1
<interactive>:0:11:
No instance for (Num ([a0] -> a0))
arising from the literal `1'
Possible fix: add an instance declaration for (Num ([a0] -> a0))
In the first argument of `maxFactor', namely `1'
In the expression: maxFactor 1
In an equation for `it': it = maxFactor 1
Однако я не понимаю этого поведения:
fac
:
fac :: Integral a => a -> [a]
в то время как тип maxFactor
:
maxFactor :: Integral ([a] -> a) => ([a] -> a) -> [a] -> a
Не означает ли это следующее:
- первый вход в
fac
должен иметь тип Integral
(например, fac 10
);
- так как в определении
maxFactor
существует fac x
, x также должен быть класса typeclass Integral
, таким образом, тип maxFactor
начинался бы с чего-то вроде maxFactor :: (Integral a) => a ->
... затем что-то еще? Однако, если это так, то почему этот код компилируется, поскольку возврат maxFactor
может быть x
или head
, который, следуя этой строке рассуждений, не имеет одного и того же типа?
Что мне здесь не хватает?
Спасибо за любые вводы заранее!
Ответы
Ответ 1
in maxFactor
компилятор сообщает, что аргумент функции x
обязательно имеет тот же тип, что и head
(в вашем предложении if
). Поскольку вы также вызываете fac
на x
(который, в свою очередь, вызывает mod
), он указывает, что x
также является некоторым типом класса Integral
. Следовательно, компилятор отображает тип
maxFactor :: Integral ([a] -> a) => ([a] -> a) -> [a] -> a
который принимает некоторый head
-подобный и целочисленный аргумент... который вряд ли будет реальным.
Я думаю, что тот факт, что вы можете загрузить этот код в GHCi, - скорее причуда интерпретатора. Если вы просто компилировали вышеприведенный код, он потерпит неудачу.
Изменить: я думаю, проблема в том, что средство проверки типов может понять ваш код, однако, вероятно, нет разумного способа его использования.
Ответ 2
Как вы заметили правильно, использование функции fac
внутри maxFactor
добавляет ограничение Integral a
на тип x
. Поэтому x
должен иметь тип Integral a => a
.
Кроме того, компилятор видит, что maxFactor
возвращает head
, который имеет тип [a]->a
или x
. Следовательно, x
должен иметь более специфический тип Integral ([a]->a) => ([a]->a)
, и поэтому maxFactor
имеет тип
maxFactor :: Integral ([a] -> a) => ([a] -> a) -> ([a] -> a)
что и есть то, что вы получили. Пока что нет ничего "неправильного" в этом определении. Если вам удалось написать экземпляр Integral
type ([a]->a)
, вы могли бы вызвать maxFactor
без проблем. (Очевидно, что maxFactor
не работает должным образом.)