2012-04-12 12 views
9

desidero generare un piuttosto grande ma finito prodotto cartesiano in Haskell, che devo poi iterare su (si pensi funzione di partizione di un modello di campo medio). La cosa più naturale da fare usa sequence, in questo modo:prodotto cartesiano Lazy Haskell

l = sequence $ replicate n [0,1,2] 

Purtroppo, per grandi n, questo non va bene nella memoria e io a corto di cumulo non appena chiedo length l per esempio. Avrei bisogno di un modo per fare la stessa cosa pigramente. Ho finito per "riscoprire" base-3 aritmetica, in questo modo,

nextConfig []  = [] 
nextConfig (0:xs) = 1:xs 
nextConfig (1:xs) = 2:xs 
nextConfig (2:xs) = 0:(nextConfig xs) 

ll = take (3^n) $ iterate nextConfig $ replicate n 0 

(che funziona), ma ci si sente come reinventare la ruota, e inoltre è troppo specifica. Quale sarebbe il modo migliore per generare il prodotto?

+0

Ti interessa l'ordine degli elementi nel risultato? – augustss

+0

No, purché non ci sia ripetizione. –

+0

Quanto è grande? N? Essere? – dave4420

risposta

5

Il modo più memoria-friendly si ottiene legando in ordine inverso rispetto alla sequenza,

foo 0 _ = [[]] 
foo k xs = [h:t | t <- foo (k-1) xs, h <- xs] 

E 'più lento a causa di meno la condivisione, ma dal momento che la memoria è il vostro problema, forse è abbastanza buono per voi.

+0

Cool! Dovrò indagare di più sul perché funzioni, ma certamente lo fa. L'ho modificato come 'foo (l: ls) = [h: t | t <- foo2 ls, h <- l] '(chissà se avrò sempre bisogno di un cubo) e funziona pure. Grazie! –

+0

Perché la comprensione delle liste è più efficiente della notazione delle liste (che è usata in 'sequenza')? Riesco a vedere dal rapporto Haskell2010 che entrambi hanno desugar su 'concatMap'? – haskelline

+2

@brence: vedi la risposta di Duncan Coutts a questa domanda reddit: [Perché le guardie nella comprensione delle liste sono più veloci che nella do notazione?] (Http://www.reddit.com/r/haskell/comments/oolyt/why_are_guards_in_the_list_comprehension_faster /) – danr

Problemi correlati