Riffing sulla risposta di sepp2k, questo è un eccellente esempio per mostrare la differenza tra Functor
e Monad
.
La definizione standard Haskell di Monad
va qualcosa come questo (semplificato):
class Monad m where
return :: a -> m a
(>>=) :: m a -> (a -> m b) -> m b
Tuttavia, questo non è l'unico modo in cui la classe avrebbe potuto essere definito. Un'alternativa corre come questo:
class Functor m => Monad m where
return :: a -> m a
join :: m (m a) -> m a
Dato che, è possibile definire >>=
in termini di fmap
e join
:
(>>=) :: Monad m => m a -> (a -> m b) -> m b
ma >>= f = join (f <$> ma)
Vedremo questo in uno schema semplificato del problema si è imbattersi. Quello che stai facendo può essere schematizzato in questo modo:
ma :: IO a
f :: a -> IO b
f <$> ma :: IO (IO b)
Ora sei bloccato in quanto è necessario un IO b
, e la classe Functor
non ha alcuna operazione che ti arriva da IO (IO b)
. L'unico modo per arrivare dove si vuole è quello di immergersi in Monad
, e l'operazione join
è precisamente ciò che lo risolve:
join (f <$> ma) :: IO b
Ma la definizione join
/<$>
di >>=
, questo è lo stesso:
ma >>= f :: IO a
Si noti che la libreria Control.Monad
viene fornita con una versione di join
(scritta in termini di return
e (>>=)
); potresti metterlo nella tua funzione per ottenere il risultato desiderato. Ma la cosa migliore da fare è riconoscere che ciò che stai cercando di fare è fondamentalmente monadico, e quindi che lo <$>
non è lo strumento giusto per il lavoro. Stai dando il risultato di un'azione all'altra; che intrinsecamente richiede l'utilizzo di Monad
.
fonte
2013-05-25 17:56:39
la mia sensazione intuitiva è utile: 'removeFile' aggiunge 1 effetto.se vogliamo solo 1 effetto alla fine, dobbiamo dare da mangiare se qualcosa con effetto 0. 'lst' ha già un effetto. quindi dobbiamo rimuoverlo prima, usando il bind che (stage a computation that) esegue l'effetto per ottenere il valore con l'effetto 0 – nicolas