Riffing na odpowiedź sepp2k, jest to doskonały przykład, aby pokazać różnicę między Functor
i Monad
.
Standardowa definicja Haskell z Monad
idzie coś takiego (uproszczony):
class Monad m where
return :: a -> m a
(>>=) :: m a -> (a -> m b) -> m b
Jednakże, nie jest to jedyny sposób, klasa mogła zostać zdefiniowane. Alternatywą przebiega tak:
class Functor m => Monad m where
return :: a -> m a
join :: m (m a) -> m a
Biorąc pod uwagę, że można zdefiniować >>=
pod względem fmap
i join
:
(>>=) :: Monad m => m a -> (a -> m b) -> m b
ma >>= f = join (f <$> ma)
Przyjrzymy się to w sposób uproszczony szkic problemu jesteś biegnąc do. Co robisz można schematycznie tak:
ma :: IO a
f :: a -> IO b
f <$> ma :: IO (IO b)
Teraz utkniesz ponieważ potrzebny jest IO b
, a klasa Functor
ma operację, która będzie Ci tam z IO (IO b)
. Jedynym sposobem, aby dostać się tam, gdzie chcesz się zanurzyć się Monad
, a operacja join
jest właśnie to, co rozwiązuje go:
join (f <$> ma) :: IO b
Ale definicją >>=
join
/<$>
, jest taka sama, jak:
ma >>= f :: IO a
Należy pamiętać, że biblioteka Control.Monad
jest dostarczana z wersją join
(zapisaną w kategoriach return
i (>>=)
); możesz umieścić to w swojej funkcji, aby uzyskać pożądany rezultat. Lepiej jednak jest rozpoznać, że to, co próbujesz zrobić, jest zasadniczo monadyczne, a zatem <$>
nie jest właściwym narzędziem do tego zadania. Karmisz wynik jednej akcji innej osobie; to samo w sobie wymaga użycia Monad
.
moje intuicyjne uczucie, które pomaga: 'removeFile' dodaje 1 efekt.jeśli chcemy tylko jednego efektu na końcu, musimy nakarmić, jeśli coś z efektem 0. 'lst' już działa. więc musimy go najpierw usunąć, używając wiązania, które (wykonując obliczenia) uruchamia efekt, aby uzyskać wartość z efektem 0 – nicolas