Ho bisogno di calcolare foo n = maximumBy (comparing p) [1..n]
, dove p :: Int -> Int
è lento. Ma so che p n < n
per tutti n > 0
e voglio usare questo fatto per accelerare questo calcolo nel seguente modo: computo p x
per a partire da n
fino a 1
, memorizzando il massimo corrente. Una volta raggiunto lo x
minore o uguale al massimo corrente, so che questo massimo deve essere quello globale e che ho finito.Idiomatic codice Haskell per semplificare la ricorsione
Quindi il mio tentativo assomiglia a questo:
foo n = go (0, 0) n where
go (c, _) 1 = c
go (c, c') !x = if c' >= x then c else go (c2, c'2) (x-1) where
x' = p x
(c2, c'2) = if c' >= x' then (c, c') else (x, x')
Questo funziona, ma non sembra molto idiomatica. Quindi sto cercando una soluzione più elegante. Hai suggerimenti?
Sbarazzarsi della coppia, lo rendono 'andare xyn ...', e vorrei legare 'pn' a un nome (don possiamo anche dare al compilatore la possibilità di ricalcolarlo), altrimenti è quello che farei. Semplice, chiaro, efficiente. –
Grazie, sostituisci la coppia come hai suggerito, è decisamente meglio. Ad ogni modo, devo ammettere che ho esitato a usare un let ... in binding poiché non so davvero se nel mio secondo pattern matching, il (pn) sarà calcolato due volte o meno. Se devo giustificare il mio codice, direi che Haskell è pigro per natura, questo significa che la strategia di valutazione è chiamata per necessità e per definizione "Call-by-need è una versione memoized di call-by-name", allora dovrebbe essere ok, no? Come è vero che usando un let in binding come hai suggerito di non lasciare spazio a dubbi, ho aggiunto il tuo suggerimento sotto il mio. – zurgl
Io userei un 'dove'. 'vai x y n | n == 1 || n <= y = x | pn> y = go n pn (n-1) | altrimenti = vai x y (n-1) dove pn = p n'. –