2012-03-18 11 views
6

Immagina di dover passare una sequenza e di conoscere anche i valori intermedi in diversi punti lungo l'intervallo. Questo è quello che ho usato per questo:Qual è questo modello di piegatura e iterazione?

[a,b,c] = map fst . tail $ chain [g i, g j, g k] (zero, sequence) 

g :: Integer -> (a,b) -> (a,b) 

chain (f:fs) x = x : chain fs (f x) 
chain [] x = [x] 

La funzione g consuma una certa parte di una sequenza di ingresso (di lunghezza i, j, ecc), iniziando con un valore di partenza e producendo risultati della stessa digitare, da inserire nella prossima invocazione. Consumare più volte la sequenza per lunghezze diverse a partire dall'inizio e lo stesso valore iniziale sarebbe inefficiente, ovviamente sia in termini di tempo che di spazio.

Quindi da una parte pieghiamo su questa sequenza di numeri interi - punti intermedi sulla sequenza; d'altra parte iteriamo questa funzione, g. Che cos'è? Mi sto perdendo qualcosa di base qui? Questo può essere espresso in qualche modo con il repertorio regolare di pieghe, ecc.?

EDIT:   risolto:   quanto sopra è semplicemente

[a,b,c] = map fst . tail $ scanl (flip g) (zero, sequence) [i, j, k] 

interessante come un'iterazione modificabile effettivamente è ripiegare l'elenco dei modificatori.

+6

Praticamente vuoi dire scanl? http://www.haskell.org/hoogle/?hoogle=scanl – Marcin

+1

@Marcin ah, sì, le cose di base. Probabilmente sì. Ciò che mi ha confuso era che 'g' stesso ripiega anche sulla sequenza. Immagino che la funzione di scansione combinerebbe '(zero, sequenza)' con 'i' e scansionerà direttamente l'elenco' [i, j, k] '... Grazie, ci proverò! –

risposta

9

Prova scanl: http://www.haskell.org/hoogle/?hoogle=scanl

scanl è simile a foldl, ma restituisce un elenco di successive ridotti valori da sinistra:

scanl f z [x1, x2, ...] == [z, z `f` x1, (z `f` x1) `f` x2, ...] 

Nota che

last (scanl f z xs) == foldl f z xs 
4

Per approfondire Il commento di Marcin, che, fondamentalmente, vogliono:

intermediates = scanl step zero sequence 
map (\n -> intermediates !! n) [i, j, k] 

step non è g, ma solo la parte di g che consuma un singolo elemento della lista sequence.

Inoltre, accetta Marcin come risposta corretta.

+0

la sequenza stessa è enorme (beh, * grande *), e ho solo bisogno di due intermedi e una finale. L'intera faccenda è ridurre il consumo di spazio e dare a ghc la possibilità di sbarazzarsi del maggior numero possibile di cose. Inoltre, ho accettato 5 minuti prima del tuo post. :) Grazie! –

+0

Se si compila quanto sopra con le ottimizzazioni, GHC dovrebbe automaticamente raccogliere i risultati intermedi che non si utilizzano, quindi dovrebbe essere eseguito in uno spazio costante. Non è più costoso che se tu stessi facendo le pieghe intermedie a mano. –

+0

Ho il sospetto che '(!! n)' richiederà l'esistenza dell'intera sequenza poiché deve iniziare a contare dall'inizio. Ma ci proverò più tardi, grazie.Ogni valore precedente è necessario per produrre il successivo; anche se non è più necessario è un sacco di attività (gc), e la lista stessa verrà mantenuta, quindi potrebbe anche non liberare il valore di ogni nodo come era già forzato. Quando si calcola per step è esattamente ciò che viene evitato, si spera. Ho effettivamente visto un calo significativo delle dimensioni dello spazio con il mio approccio. –

Problemi correlati