Sono curioso come ottimizzare questo codice:Ottimizzazione calcolo parziale in Haskell
fun n = (sum l, f $ f0 l, g $ g0 l)
where l = map h [1..n]
Supponendo che f
, f0
, g
, g0
e h
sono tutti costosi, ma la creazione e lo stoccaggio di l
è estremamente costoso.
Come scritto, l
viene memorizzato fino a quando la tupla restituita è completamente valutata o raccolta dati inutili. Invece, length l
, f0 l
e g0 l
devono essere tutti eseguiti ogni volta che uno di essi viene eseguito, ma f
e g
devono essere ritardati.
Sembra questo comportamento poteva essere risolto scrivendo:
fun n = a `seq` b `seq` c `seq` (a, f b, g c)
where
l = map h [1..n]
a = sum l
b = inline f0 $ l
c = inline g0 $ l
O il molto simile:
fun n = (a,b,c) `deepSeq` (a, f b, g c)
where ...
Potremmo forse indicare una serie di tipi di interni per ottenere gli stessi effetti pure, che sembra doloroso. Ci sono altre opzioni?
Inoltre, sto ovviamente sperando con i miei inline
s che il compilatore fusibili sum
, f0
, e g0
in un unico ciclo che costruisce e consuma l
termine a termine. Potrei renderlo esplicito attraverso l'inlining manuale, ma quello farebbe schifo. Esistono modi per impedire esplicitamente che l'elenco l
venga creato e/o forzato l'inlining? Direttive che producono avvertimenti o errori se l'inlining o la fusione falliscono durante la compilazione forse?
Per inciso, io sono curioso di sapere il motivo per cui seq
, inline
, lazy
, ecc sono tutti definito dal let x = x in x
nel preludio. È semplicemente per dare loro una definizione per il compilatore di scavalcare?
In risposta all'ultima domanda: http://stackoverflow.com/a/8654407/1011995 –
Sono 'f0' e' g0' del tutto arbitrari, o possono essere scritti in termini di 'foldr'? – dave4420
Non sarebbe sufficiente una semplice piega con un accumulatore (a, b, c)? – Sarah