Un programmatore Clojure so che recentemente ho osservato che è possibile implementare molte funzioni di sequenza in termini di Clojure reduce
(che è Haskell foldl'
), ma purtroppo non c'è modo di implementare (map list xs ys)
(che è Haskell zip
) con solo reduce
.Come implementare zip con foldl (in una lingua ansiosa)
Ora, ho letto su l'universalità di pieghe, quindi sono abbastanza sicuro che questo non è vero: certamente zip
è possibile con foldr
, e sarei sorpreso se non fosse possibile con foldl
. Ai fini di questa discussione ignoriamo i problemi dell'entusiasmo di foldl
rispetto a foldr
: immaginiamo di avere memoria illimitata e lavorare solo con sequenze finite.
Così, ho preso il codice Haskell per implement zip with foldr, e tradotti al Clojure, facendo del mio meglio per regolare la differenza tra foldr e foldl:
(defn zip [xs ys]
(letfn [(done [_] [])
(step [z x]
(fn [ys]
(if (empty? ys)
[]
(conj (z (rest ys)) [x (first ys)]))))]
((reduce step done xs) ys)))
user> (zip [1 2] '[a b c]) ;=> [[1 b] [2 a]]
E infatti noi otteniamo coppie di elementi da xs e ys sono insieme, ma fuori ordine: il primo elemento di xs è accoppiato con l'ultimo elemento di ys, e così via lungo la linea. Posso vedere la causa del problema: la funzione che produciamo consuma a partire da sinistra, ma la chiusura più esterna (che è chiamata prima) ha chiuso sull'ultimo elemento di xs, quindi non può accoppiarli a destra ordine.
Penso che la soluzione sia quella di costruire in qualche modo le chiusure all'interno, ma non riesco davvero a vedere come farlo. Accetterei volentieri una soluzione sia in Haskell che in Clojure.
Sto sperando in una soluzione del modulo zip = foldl f x
, in modo che possa dire che è "solo" una riduzione. Ovviamente posso invertire uno degli elenchi, ma alla fine sembra zip xs ys = foldl f x xs $ reverse ys
che non sembra molto soddisfacente o pulito.
Se non ti interessa l'efficienza, puoi usare 'init' invece di' tail' e/o '++ [a]' invece di 'a:'. – dfeuer
In alternativa, puoi trovare un'implementazione di 'foldr' in termini di' foldl' (per gli elenchi finiti) su Internet. – dfeuer
Bene, sto usando 'conj' nella versione Clojure, che è una versione efficiente di' ++ [a] '(usando una struttura dati diversa da liste collegate). Questo in realtà non lo risolve: puoi ottenere sia xs che ys nel giusto ordine, ma non in entrambi i modi ovvi che riesco a vedere. – amalloy