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 не работает должным образом.)