[Haskell-beginners] newbie: Monad, equivalent notation using Control.Monad.guard

Brent Yorgey byorgey at seas.upenn.edu
Tue Oct 18 12:52:01 CEST 2011


On Tue, Oct 18, 2011 at 10:52:57AM +0100, Hugo Ferreira wrote:
> Hello,
> 
> On 10/17/2011 05:22 PM, Brent Yorgey wrote:
> >On Mon, Oct 17, 2011 at 04:18:05PM +0100, Hugo Ferreira wrote:
> >>Hello,
> >>
> >>I came across the following code:
> >>
> >>ngrams'' :: Int ->  [a] ->  [[a]]
> >>ngrams'' n l = do
> >>   t<- Data.List.tails l
> >>   l<- [take n t]
> >>   Control.Monad.guard (length l == n)
> >>   return l
> >>
> >>and tried to use the ">>=" operator in order
> >>to figure out how Monads work. I came up with:
> >>
> >>test l =
> >>    (Data.List.tails l)
> >>    >>= (\t ->  [take 2 t])
> >>    >>= (\l ->  if (length l == 2) then [l] else [])
> >>
> >>Questions:
> >>1. How can I use Control.Monad.guard directly in "test l"
> >
> >test l =
> >     (Data.List.tails l)
> >     >>= \t ->  [take 2 t]
> >     >>= \l ->  Control.Monad.guard (length l == 2)
> >     >>   return l
> >
> >The rule is that
> >
> >   x<- foo
> >
> >desugars to
> >
> >   foo>>= \x ->  ...
> >
> >and
> >
> >   blah
> >
> >desugars to
> >
> >   blah>>  ...
> >
> 
> Ok, I was not aware of the >>.
> 
> >One thing that might have been tripping you up is your extra
> >parentheses around the lambda expressions.  If you have
> >
> >   >>= (\l ->  ...)
> >   >>   foo...
> >
> >the l does not scope over foo... so you cannot mention it.  Instead
> >what you want is
> >
> >   >>= \l ->  ...
> >   >>   foo...
> >
> >so the lambda expression is actually   \l ->  ...>>  foo..., that is,
> >it includes *everything* after the \l ->  ... and not just the stuff on
> >that line.
> >
> 
> Hmmm. Still cannot wrap my mind around this B-(.
> 
> [[1],[2],[3]] >>= \l -> func1 l >>= \m -> func2 m
> 
> \l will hold each of the 3 elements of initial list
>    these are concatenated with the results of func1
>    results in a new list
> 
> \m will have each element in the new list
>    these are concatenated with the results of func2
>    results in a last list
> 
> is equal to ?
> 
> (([[1],[2],[3]] >>= \l -> func1 l) >>= \m -> func2 m)

Yes, your description is correct, and yes, these are equal. (Although
the first is often more efficient.)  They are required to be equal by
the monad laws. However, consider

  [[1],[2],[3]] >>= \l -> func1 l >>= \m -> func2 m l

and

  (([[1],[2],[3]] >>= \l -> func1 l) >>= \m -> func2 m l)

Notice that func2 now takes a second argument.  There is not even a
question of whether these are equal: the second does not even compile,
because the final 'l' is not in scope.  This is the point I was trying
to make.

-Brent



More information about the Beginners mailing list