Cosa c'è di sbagliato con la mia definizione di zip in Haskell?
-
23-09-2019 - |
Domanda
-- 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 ]
ricevo questo messaggio di errore:
Occurs check: cannot construct the infinite type: a = [a]
When generalising the type(s) for `myzip'
Failed, modules loaded: none.
Soluzione
Ci sono tre problemi: uno è il pattern match, uno è la firma di tipo, e uno è la natura della lista di comprensione. Ecco una versione corretta:
{-# LANGUAGE ParallelListComp #-}
myzip :: [a] -> [b] -> [(a, b)]
myzip xs ys = [(x, y) | x <- xs | y <- ys]
- Il tipo di firma originale,
[a] -> [a] -> [(a, a)]
, ha fatto sì che entrambe le liste dovevano avere lo stesso tipo di elemento. IlOrd a
era superfluo, e solo ha fatto sì che alcuni tipi di elementi sono stati consentiti. - Il modello
[x, _] <- list1
significa che ogni elemento dilist1
deve essere una lista a due elementi. Utilizzare invecex <- list1
. - I due list comprehension sono in serie invece che in parallelo. Pensate alla virgola come, "prendere gli oggetti da list1, poi da lista2" (serie). Pensate alle due tubi come parallelo.
La differenza tra serie e parallelo:
> [[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"]
Altri suggerimenti
Se si ri-scrittura zip
al fine di ottenere una visione in Haskell, mi suggeriscono che si tenta di scrivere senza usare list comprehensions. Di lista sono potenti, ma sono un po 'come una comoda scorciatoia per alcuni casi particolari in Haskell. E, come si vede, di utilizzarli in altri casi potrebbe richiedere estensioni non standard (come ParallelListComp
).
Pensate a cosa zip
deve fare nel caso generale, e cosa succede se il caso generale non è soddisfatta (che può avvenire in due modi!). Le equazioni per la funzione deve cadere in modo naturale da quella.