[Haskell-cafe] What pattern is this (Something.T -> IO a) in Sound.ALSA.Sequencer

Alexander Solla alex.solla at gmail.com
Sun Mar 3 20:13:37 CET 2013


On Sun, Mar 3, 2013 at 10:28 AM, Martin Drautzburg <Martin.Drautzburg at web.de
> wrote:

> Hello all,
>
> this was previously posted on Haskell Beginners, but only partially
> answered.
>
> In Sound.ALSA.Sequencer, there are a number of functions which together
> set up
> a midi environement (client, port, queue). They all have a type, where the
> last argument has a type like:
>
> (something.T -> IO a)
>

These things are in the Kleisli category for IO.  In short, an argument
with this type is a function which makes an IO action.  The function which
takes one of these as an action "knows" how to get a "something.T" to apply
to the function, either because it is an argument to the bigger function,
or because the library author knows the monad has an action with the type
IO (something.T).

This is safer than passing around unconstrained IO actions.  For example,
consider:

> outer :: String -> (Int -> IO ()) -> IO ()
versus
> outer :: String -> IO () -> IO ()

The second type requires that the library user can construct an appropriate
IO () action, and the intended dependence on the Int is not statically
verified.  On the other hand, the first type requires that you pass in an
IO () action constructor that explicitly depends on an Int.  The "only" way
you can drop the dependence on the Int is if you explicitly ignore it (and
you can turn on warnings to catch that kind of thing)


> i.e.
>
> *Main> :t SndSeq.withDefault
> SndSeq.withDefault
>   :: SndSeq.OpenMode mode =>
>      SndSeq.BlockMode -> (SndSeq.T mode -> IO a) -> IO a
>
> *Main> :t Port.withSimple
> Port.withSimple
>   :: SndSeq.T mode
>      -> String -> Port.Cap -> Port.Type -> (Port.T -> IO a) -> IO a
>
> *Main> :t Queue.with
> Queue.with :: SndSeq.T mode -> (Queue.T -> IO a) -> IO a
>
> There is example code, where a full setup is created by a number of nested
> "do" blocks. The repeating pattern there is:
>
> something1 $ \x -> do
>         something2 $ \y -> do
>                 something3 $ \z -> do
>
>
> What is this all about? I particularly would like to understand, when this
> parttern is needed and what determines the the number of nested "do"
> blocks.
>

It can be refactored, so it is never "needed".  On the other hand, it does
have nice properties.  The x,y, z variables are all in scope when you're in
something3's do-block argument.

The determining factor in the nesting depth is how many actions which take
elements of a Kliesli category for the monad will be sequenced, since each
one requires its own lambda-do-block.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.haskell.org/pipermail/haskell-cafe/attachments/20130303/ae89d9ff/attachment.htm>


More information about the Haskell-Cafe mailing list