2012-01-18 14 views
7

Come si piega rigorosamente una monade? Data.Foldable ha il severo foldl' e il monadico foldlM, ma non rigoroso foldlM'? La rigidità è in qualche modo definita dalla stessa monade? Se è così, come si fa a capire di cosa si tratta?Haskell ha foldlM '?

Immaginate di dover determinare se il prodotto di un'enorme lista di elementi dell'anello è zero, ma il mio anello non è un dominio integrale, cioè contiene zero devisori. In questo caso, dovrei tail ricorsivamente foldl la mia moltiplicazione *** nell'elenco, ma restituire False nel momento in cui il prodotto diventa zero, piuttosto che attendere il prodotto completo.

safelist :: [p] -> Bool 
safelist [] = True 
safelist (x:xs) = snd $ foldl' f (x,True) xs 
    where f (u,b) v = (w, b && w /= Zero) where w = u *** v 

potrei forse semplificare questo codice un po 'usando la monade del foldlMMaybe ma così facendo manca apparentemente il rigore necessario.

risposta

8

Non esiste una funzione standard, ma è facile da definire:

foldM' :: (Monad m) => (a -> b -> m a) -> a -> [b] -> m a 
foldM' _ z [] = return z 
foldM' f z (x:xs) = do 
    z' <- f z x 
    z' `seq` foldM' f z' xs 

Questo è solo lo standard foldM, ma con lo stesso seq ing in esso che foldl' fa (rispetto al foldl). Probabilmente non è definito ovunque standard perché non è probabile che sia tutto ciò che è utile: per la maggior parte delle monadi, (>>=) è "strict" nel senso in cui è necessario utilizzare un left-fold senza straripare lo stack; questo è utile solo quando i tuoi thunk eccessivi sono nei valori restituiti stessi, ma un'applicazione utile di foldM eseguirà alcuni calcoli monadici con il valore dell'ultimo passo, il che lo renderà improbabile.

Penso che il tuo codice sia abbastanza semplice così com'è; Dubito che lo foldM' lo renderebbe più elegante.

+0

Ah, suppongo che la monade potrebbe rendere le cose rigide se avesse bandiere rigide, ma non altrimenti. E nessuna monade standard lo fa. Grazie! –

+3

@JeffBurdges - ecco una sorta di osservazione ad-hoc di cui Monadic '>> =' sono severi contro pigri: http://stackoverflow.com/a/8250334/208257 –

+0

In effetti dubito che 'foldM'' sarebbe d'aiuto se il tuo '(>> =)' è troppo pigro, poiché ad es forzare un valore restituito dalla lazy 'State' monad non forza necessariamente lo stato. – ehird