Quanto spesso viene usato il seq nel codice di produzione Haskell?

23

Ho un po 'di esperienza nella scrittura di piccoli strumenti in Haskell e lo trovo molto intuitivo da usare, specialmente per scrivere filtri (usando interact ) che elaborano il loro input standard e lo collegano allo standard output.

Recentemente ho provato ad usare uno di questi filtri su un file che era circa 10 volte più grande del solito e ho ottenuto un errore di Stack space overflow .

Dopo aver fatto qualche lettura (es. qui e qui ) Ho identificato due linee guida per risparmiare spazio nello stack (Haskellers esperti, correggimi se scrivo qualcosa che non è corretto):

  1. Evita le chiamate ricorsive di funzioni che non sono ricorsive in coda (questo è valido per tutti i linguaggi funzionali che supportano l'ottimizzazione di coda).
  2. Introduci seq per forzare la valutazione precoce delle sottoespressioni in modo che le espressioni non diventino troppo grandi prima di essere ridotte (questo è specifico per Haskell, o almeno per le lingue che utilizzano la valutazione lazy).

Dopo aver introdotto cinque o sei% chiamate diseq nel mio codice, il mio strumento funziona di nuovo senza problemi (anche sui dati più grandi). Tuttavia, trovo che il codice originale fosse un po 'più leggibile.

Poiché non sono un programmatore Haskell esperto, volevo chiedere se introdurre seq in questo modo sia una pratica comune e quanto spesso si vedrà normalmente seq nel codice di produzione Haskell. O ci sono tecniche che permettono di evitare di usare seq troppo spesso e di usare ancora poco spazio nello stack?

    
posta Giorgio 05.10.2012 - 23:16
fonte

1 risposta

17

Sfortunatamente ci sono casi in cui si deve usare seq per ottenere un programma efficiente / funzionante per i grandi dati. Quindi, in molti casi, non puoi farne a meno nel codice di produzione. Puoi trovare ulteriori informazioni in Real World Haskell, Capitolo 25. Profilazione e ottimizzazione .

Tuttavia, ci sono possibilità su come evitare di usare seq direttamente. Questo può rendere il codice più pulito e più robusto. Alcune idee:

  1. Utilizza conduit , pipe o iteratees anziché interact . È noto che Lazy IO ha problemi con la gestione delle risorse (non solo la memoria) e le iterate sono progettate esattamente per superare questo problema. (Suggerisco di evitare l'IO pigro tutto sommato, non importa quanto grandi siano i tuoi dati - vedi Il problema con pigro I / O .)
  2. Invece di usare seq utilizza direttamente (o crea il tuo) combinatori come foldl ' o foldr ' o versioni rigide di librerie (come Data.Map.Strict o Control.Monad.State.Strict ) progettati per calcoli rigorosi.
  3. Utilizza l'estensione BangPatterns . Permette di sostituire seq con una corrispondenza di pattern rigorosa. In alcuni casi, potrebbe essere utile anche dichiarare campi di costruttori rigidi .
  4. È anche possibile utilizzare Strategie per forzare la valutazione. La libreria di strategie è principalmente rivolta a calcoli paralleli, ma ha metodi per forzare un valore a WHNF ( rseq ) o completo < a href="https://en.wikipedia.org/wiki/Normal_form_(term_rewriting)"> NF ( rdeepseq ) pure. Esistono molti metodi di utilità per lavorare con le raccolte, combinare strategie ecc.
risposta data 08.10.2012 - 23:16
fonte

Leggi altre domande sui tag