Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is (>>) supposed to discard all left-side output?

I think I do understand the list monad but then I found I am not. Here is the story.

Given list m and function k

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

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

Playing with bind >>= give what I expect

> :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]

but for >>

Expected (from experiencing with IO monad, everything on left side would be discarded)

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

Please explain why >> is not behave like I expected (of course I must have misunderstanding) and what is the correct way to interpret >> ?

like image 932
wizzup Avatar asked Feb 19 '13 08:02

wizzup


People also ask

What is discard on c#_?

Discards are placeholder variables that are intentionally unused in application code. Discards are equivalent to unassigned variables; they don't have a value.

What does _= mean in C#?

C# Hidden Gems - Discards Variable (_)Discards are equal to unassigned variables. The purpose of this feature is to use this variable when you want to intentionally skip the value by not creating a variable explicitly.


2 Answers

(>>) discards values from its first argument, but not effects. In this case it might be easier to see if you use lists with different types:

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

Note how the values of the first list aren't used at all.

Remember the definition of (>>): a >> b = a >>= (\_ -> b). So this turns into "ab" >>= (\_ -> [1,2,3,4]), i.e. concat (map (\_ -> [1,2,3,4]) ['a','b']), i.e. concat [[1,2,3,4],[1,2,3,4]] (also, [i | _ <- "ab", i <- [1,2,3,4]]).

With [], (>>=) means something like "for each". The function on the right gets as an argument each value on the left. So (>>), which discards values, still means "for each" -- but this time it can't use the value, so it just means "the elements of the second list, repeated as many times as there are elements in the first list".

like image 144
shachaf Avatar answered Mar 04 '23 13:03

shachaf


foo >> bar is the same as foo >>= \_ -> bar. So in the case of IO it executes the left action, ignoring the return value of that action, and then executes the right action. In the case of lists it maps over each element in the left list, ignoring the value of each elements, and inserts the right list at each point.

Another way to look at it is that >>= for lists is the same as flip concatMap, >> is the same as flip (concatMap . const).

like image 24
sepp2k Avatar answered Mar 04 '23 14:03

sepp2k