O que há de errado com minha definição de zíper em Haskell?
-
23-09-2019 - |
Pergunta
-- 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 ]
Eu recebo esta mensagem de erro:
Occurs check: cannot construct the infinite type: a = [a]
When generalising the type(s) for `myzip'
Failed, modules loaded: none.
Solução
Existem três problemas: um é a correspondência do padrão, uma é a assinatura do tipo e uma é a natureza da compreensão da lista. Aqui está uma versão corrigida:
{-# LANGUAGE ParallelListComp #-}
myzip :: [a] -> [b] -> [(a, b)]
myzip xs ys = [(x, y) | x <- xs | y <- ys]
- A assinatura do tipo original,
[a] -> [a] -> [(a, a)]
, significava que ambas as listas tinham que ter o mesmo tipo de elemento. oOrd a
era supérfluo e apenas significava que certos tipos de elementos eram proibidos. - O padrão
[x, _] <- list1
significa que cada elemento delist1
Deve ser uma lista de dois elementos. Usarx <- list1
em vez de. - As duas compreensões da lista são em série em vez de paralelas. Pense na vírgula como "Pegue os itens da Lista1 e depois da List2" (série). Pense nos dois tubos como paralelos.
A diferença entre séries e paralelos:
> [[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"]
Outras dicas
Se você reescrever zip
Para obter informações sobre Haskell, sugiro que você tente escrevê -lo sem usar as compreensões da lista. As compreensões da lista são poderosas, mas são um pouco como uma abreviação conveniente para alguns casos particulares em Haskell. E, como você vê, usá-los em outros casos pode exigir extensões não padrão (como ParallelListComp
).
Pensar sobre o que zip
precisa fazer no caso geral e o que acontece se o caso geral não for atendido (o que pode acontecer de duas maneiras!). As equações para a função devem cair naturalmente disso.