2012-03-15 11 views
14

Potrzebuję użyć transformatora listy Monady. Czytałem, że istnieją potencjalne problemy z ListT IO z Control.Monad.List, ponieważ IO nie jest przemienne, więc patrzę na ListT done right. Ale dostaję jakieś nieoczekiwane zachowanie.lista transformatora monady

Rozważmy prosty test:

test = runListT $ do 
    x <- liftList [1..3] 
    liftIO $ print x 
    y <- liftList [6..8] 
    liftIO $ print (x,y) 

Korzystanie Control.Monad.List:

Main> test 
1 
(1,6) 
(1,7) 
(1,8) 
2 
(2,6) 
(2,7) 
(2,8) 
3 
(3,6) 
(3,7) 
(3,8) 
[(),(),(),(),(),(),(),(),()] 

Używanie "ListT zrobione dobrze":

Main> test 
1 
(1,6) 

Czy ten problem " ListT done right ", czy też używam go nieprawidłowo? Czy istnieje preferowana alternatywa?

Dzięki!

Odpowiedz

8

To może być intensional ze strony autora, ponieważ mówią

że pozwala każdy element listy posiada własnych efektów ubocznych, które tylko się `ścięci” jeśli ten element listy jest naprawdę sprawdzony.

Nie jestem jednak pewien. W każdym razie, można użyć tej funkcji do sekwencjonowania całą listę :

runAll_ :: (Monad m) => ListT m a -> m() 
runAll_ (ListT m) = runAll_' m where 
    runAll_' m = do 
     mm <- m 
     case mm of 
      MNil   -> return() 
      _ `MCons` mxs -> runAll_' mxs 

i analogiczną runAll że zwraca listę powinien być łatwy do skonstruowania.

main = runAll_ $ do 
    x <- liftList [1..3] 
    liftIO $ print x 
    y <- liftList [6..8] 
    liftIO $ print (x,y) 

1 
(1,6) 
(1,7) 
(1,8) 
2 
(2,6) 
(2,7) 
(2,8) 
3 
(3,6) 
(3,7) 
(3,8) 
+0

Hmm, OK to ma sens, a twój pomysł "runAll_" jest całkiem niezły! Oczekiwano zachowania podobnego do zagnieżdżonego dla pętli z instrukcjami print w języku imperatywnym. Ale jeśli "ListT done right" jest leniwy, dlaczego wciąż wywołuje efekty uboczne dla szefów list? –

+0

Przyjmuje, że zawsze chcesz co najmniej pierwszego elementu, więc owija on "całą listę" w 'm', a także opakowuje cdr w' m'; samochód nie jest zapakowany. Jeśli wykonasz sekwencję "całej listy", eksponujesz tylko samochód. – Owen