Вот трюк, который мне очень помог при проблемах с типами. Всякий раз, когда я полностью сбит с толку таким сообщением, я делаю следующее:
- Если в рассматриваемой функции есть сигнатура типа, удалите ее и посмотрите, изменится ли что-нибудь. Если он скомпилируется, спросите у ghci, какой это тип (используя
:t
). Если он не скомпилируется, по крайней мере, сообщение об ошибке может отличаться достаточно, чтобы дать вам еще одну подсказку.
- Если подписи типа нет, добавьте ее. Даже если он не скомпилируется, сообщение об ошибке может дать вам еще одну подсказку.
- Если это не поможет, временно добавьте объявления типов для каждого выражения в функции. (Часто вам нужно разбить некоторые выражения, чтобы увидеть, что происходит на самом деле. Вам также может понадобиться временно включить прагму
ScopedTypeVariables
.) Снова скомпилируйте и проверьте сообщения об ошибках.
Это последнее упражнение требует больше работы, но я многому научился из этого упражнения. Обычно это точно определяет место, где есть несоответствие между тем, что я думаю о типе, и тем, что GHC думает о типе.
Итак, давайте начнем с добавления сигнатур типов в ваш код:
myrepli :: [a] -> Int -> [a]
myrepli [] n = []
myrepli [x] 0 = []
myrepli [x] n = (x:(myrepli [x] (n-1)))
repli :: [a] -> Int -> [a]
repli [] n = []
repli (x:xs) n = (myrepli x n) ++ (repli xs n) -- triggers a compiler error
А, теперь мы получаем ошибку компилятора:
amy.hs:9:27:
Couldn't match expected type `a' with actual type `[a]'
`a' is a rigid type variable bound by
the type signature for repli :: [a] -> Int -> [a] at amy.hs:7:10
In the first argument of `myrepli', namely `x'
In the first argument of `(++)', namely `(myrepli x n)'
In the expression: (myrepli x n) ++ (repli xs n)
Проблема в вызове myrepli x n
. Функция myrepli
ожидает список/строку, но вы передаете ей один символ. Измените последнюю строку на:
repli (x:xs) n = (myrepli [x] n) ++ (repli xs n)
В этот момент вы найдете другие ошибки в вашем коде. Но вместо того, чтобы исправлять ваш код, позвольте мне показать вам другой способ сделать это:
repl (x:xs) n = (myReplicate x n) ++ (repl xs n)
repl [] _ = []
-- You could use the library function "replicate" here, but as a
-- learning exercise, we'll write our own.
myReplicate a n = take n (repeat a)
person
mhwombat
schedule
18.02.2014