2013-02-19 7 views
12

Myślę, że rozumiem monadę z listy , ale potem okazało się, że nie jestem. Oto historia.Czy (>>) ma odrzucić wszystkie lewe wyjście?

danej listy m i funkcja k

> let m = [1..10] 
> :t m 
m :: [Integer] 

> let k = replicate 2 
> :t k 
k :: a -> [a] 

Playing with wiążą >>= dać to, czego oczekuję

> :t (>>=) 
(>>=) :: Monad m => m a -> (a -> m b) -> m b 
> :t m >>= k 
m >>= k :: [Integer] 
> m >>= k 
[1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10] 

ale >>

Oczekiwany (z doświadczenia z IO monady, wszystko na lewo strona zostanie odrzucona)

m >> m 
[1,2,3,4,5,6,7,8,9,10] 

Got

> :t (>>) 
(>>) :: Monad m => m a -> m b -> m b 
:t m >> m 
m >> m :: [Integer] 
> m >> m 
[1,2,3,4,5,6,7,8,9,10,1,2,3,4,5 ... 9,10] -- truncated, real output is 100 elements 

proszę wyjaśnić dlaczego >> nie zachowują się tak jak się spodziewałem (oczywiście muszę mieć nieporozumień) i jaki jest właściwy sposób interpretacji >>?

Odpowiedz

25

(>>) odrzuca wartości wartości od z pierwszego argumentu, ale bez efektów. W tym przypadku może to być łatwiejsze do zauważenia w przypadku korzystania z list różnych typów:

λ> "ab" >> [1,2,3,4] 
[1,2,3,4,1,2,3,4] 

Zauważ, że wartości pierwszej listy nie są w ogóle stosowane.

Zapamiętaj definicję (>>): a >> b = a >>= (\_ -> b). Zatem zmienia się to w "ab" >>= (\_ -> [1,2,3,4]), tj. concat (map (\_ -> [1,2,3,4]) ['a','b']), tj. concat [[1,2,3,4],[1,2,3,4]] (także, [i | _ <- "ab", i <- [1,2,3,4]]).

Z [], (>>=) oznacza coś w stylu "dla każdego". Funkcja po prawej dostaje jako argument każdą wartość po lewej stronie. Tak więc (>>), która odrzuca wartości, nadal oznacza "dla każdego" - ale tym razem nie może użyć wartości, więc po prostu oznacza "elementy drugiej listy, powtarzane tyle razy, ile elementów na pierwszej liście ".

+0

Wow! co za jasną (i bardzo szybką) odpowiedź. Dzięki – wizzup

12

foo >> bar jest taki sam jak foo >>= \_ -> bar. Tak więc w przypadku IO wykonuje lewą akcję, ignorując wartość zwracaną tej akcji, a następnie wykonuje właściwą akcję. W przypadku list mapuje on każdy element na lewej liście, ignorując wartość każdego elementu i wstawia prawą listę w każdym punkcie.

Innym sposobem, aby spojrzeć na to jest fakt, że >>= dla list jest taki sam jak flip concatMap, >> jest taka sama jak flip (concatMap . const).

+0

Dziękuję też, Szkoda, że ​​mogę wybrać tylko jedną akceptowaną odpowiedź. – wizzup

Powiązane problemy