[Haskell-beginners] Please explain the "$ \foo ->do" idiom

Martin Drautzburg Martin.Drautzburg at web.de
Sat Feb 9 10:41:59 CET 2013


On Friday, 8. February 2013 08:26:38 Henk-Jan van Tuyl wrote:
> On Wed, 06 Feb 2013 22:31:05 +0100, Martin Drautzburg
> 
> <Martin.Drautzburg at web.de> wrote:
> > Can
> > someone please walk me through it and possibly show ways to avoid the
> > massive
> > nesting.
> > 
> > dtz = do
> > 
> >     SndSeq.withDefault SndSeq.Block $ \h -> do
> >     
> >       Client.setName (h :: SndSeq.T SndSeq.DuplexMode) "Haskell-Melody"
> >       Port.withSimple h "out"
> >       
> >         (Port.caps [Port.capRead, Port.capSubsRead, Port.capWrite])
> >         (Port.types [Port.typeMidiGeneric, Port.typeApplication]) $ \p
> > 
> > -> do
> > 
> >             Queue.with h $ \q -> do
> >             
> >               c <- Client.getId h
> >               let me = Addr.Cons c p
> >               conn <- parseDestArgs h me ["20:0"]
> >               Queue.control h q Event.QueueStart Nothing
> >               Queue.control h q (Event.QueueTempo (Event.Tempo
> > 
> > 10000000)) Nothing
> > 
> >               return ()
> 
> I like to divide large functions into several smaller ones:
> 
> dtz =
>    SndSeq.withDefault SndSeq.Block f1
>      where
>        f1 h =
>          do
>            Client.setName (h :: SndSeq.T SndSeq.DuplexMode)
> "Haskell-Melody" Port.withSimple h "out"
>              (Port.caps [Port.capRead, Port.capSubsRead, Port.capWrite])
>              (Port.types [Port.typeMidiGeneric, Port.typeApplication]) (f2
> h)
>        f2 h p = Queue.with h (f3 h p)
>        f3 h p q =
>          do
>            c <- Client.getId h
>            let me = Addr.Cons c p
>            conn <- parseDestArgs h me ["20:0"]
>            Queue.control h q Event.QueueStart Nothing
>            Queue.control h q (Event.QueueTempo (Event.Tempo 10000000))
> Nothing
>            return ()

I tried to do exactly this and I like it a bit better. But note how those 
functions get quite a number of parameters. In the nested "do", evertything 
was in scope.

Things get worse, when I try to run something in the innermost "do". When I 
use individual functions, I need yet another parameter which needs to travel 
through all these functions. As Brent Yorgey suggested, the nested "do"s can 
accept another parameter in the topmost function and it will be automatically 
in scope all the way down.

I really wish, someone could elaboreate on this "$ \foo ->do" pattern,

- when it is typically used, 
- what determines the depth of the nesting, 
- its pros and cons and the possible alternatives. 

It seems to be some kind of idiom,
-- 
Martin



More information about the Beginners mailing list