Что не так с моим определением Zip в Haskell?
-
23-09-2019 - |
Вопрос
-- eg. myzip [’a’, ’b’, ’c’] [1, 2, 3, 4] -> [(’a’, 1), (’b’, 2), (’c’, 3)]
myzip :: Ord a => [a] -> [a] -> [(a,a)]
myzip list1 list2 = [(x,y) | [x, _] <-list1, [y,_] <-list2 ]
Я получаю это сообщение об ошибке:
Occurs check: cannot construct the infinite type: a = [a]
When generalising the type(s) for `myzip'
Failed, modules loaded: none.
Решение
Есть три проблемы:Первый - это соответствие шаблону, второй - сигнатура типа, и третий - характер понимания списка.Вот исправленная версия:
{-# LANGUAGE ParallelListComp #-}
myzip :: [a] -> [b] -> [(a, b)]
myzip xs ys = [(x, y) | x <- xs | y <- ys]
- Подпись исходного типа,
[a] -> [a] -> [(a, a)]
, означало, что оба списка должны были иметь элемент одного и того же типа.ВOrd a
был излишним и просто означал, что определенные типы элементов были запрещены. - Закономерность
[x, _] <- list1
означает , что каждый элементlist1
должен быть список из двух элементов.Использованиеx <- list1
вместо этого. - Два понимания списка расположены последовательно, а не параллельно.Думайте о запятой как о "Взять элементы из list1, затем из list2" (серия).Думайте о двух трубах как о параллельных.
Разница между последовательным и параллельным:
> [[x, y] | x <- "abc", y <- "123"] -- series
["a1","a2","a3","b1","b2","b3","c1","c2","c3"]
> [[x, y] | x <- "abc" | y <- "123"] -- parallel
["a1","b2","c3"]
Другие советы
Если вы переписываете zip
чтобы получить представление о Haskell, я бы посоветовал вам попробовать написать его без использования понимания списков.Понимание списков является мощным, но чем-то похоже на удобное сокращение для некоторых конкретных случаев в Haskell.И, как вы видите, для их использования в других случаях может потребоваться нестандартные расширения (такие как ParallelListComp
).
Думать о чем zip
что нужно сделать в общем случае, и что произойдет, если общий случай не будет выполнен (что может произойти двумя способами!).Уравнения для функции должны естественным образом вытекать из этого.