[Haskell-cafe] Bracket around every IO computation monad

C. McCann cam at uptoisomorphism.net
Mon Nov 15 15:07:44 EST 2010


On Sun, Nov 7, 2010 at 7:40 PM, Mitar <mmitar at gmail.com> wrote:
> I have a class Neuron which has (among others) two functions: attach
> and deattach. I would like to make a way to call a list/stack/bunch of
> attach functions in a way that if any of those fail (by exception),
> deattach for previously already attached values (called attach on
> them) are deattached (called deattach on them).
>

Perhaps I'm misunderstanding how this works, but it seems like this
could all be done fairly simply using standard combinators in
Control.Monad.

> growNeurons :: [IO Growable] -> IO [Growable]
> growNeurons attaches = growNeurons' attaches []
>  where growNeurons' [] ls      = return ls
>        growNeurons' (a:ats) ls = bracketOnError a (\(Growable l) ->
> deattach l) (\l -> growNeurons' ats (l:ls))

Isn't this mostly a reimplementation of mapM? Given a list of [IO
Growable], you map over it to put a bracket around each one, then
sequence the result (which I believe performs exactly the sort of
nested monadic recursion you're doing here). I think that something
like this ought to be equivalent:

growNeurons :: [IO Growable] -> IO [Growable]
growNeurons = mapM (\a -> bracketOnError a (\(Growable l) -> deattach l) return)

> So I give growNeurons a list of attach actions and it returns a list
> of attached values ((live)neurons). This works nice, but syntax to use
> it is ugly:
>
> neurons <- growNeurons [
>    do { a <- attach nerve1; return $ Growable a },
>    do { a <- attach nerve2; return $ Growable a },
>    do { a <- attach nerve3; return $ Growable a }
>  ]

Along the lines of what Felipe suggested, this could possibly be
simplified to something like:

growNeurons  $ map (fmap Growable . attach) [nerve1, nerve2, nerve3]

...except that this won't work if the nerves have different types. In
many cases there's a trivial translation to get rid of existential
types, and I suspect it would work here, but I'm not sure what else
you might be doing with them. Existential types tend to be more
trouble than they're worth, in my experience.

> It seems to me that all this could be wrapped into a monad. So that I
> would be able to call something like:
>
> neurons <- growNeurons' $ do
>    attach nerve1
>    attach nerve2
>    attach nerve3

I'm not sure why you'd want to do it this way, relying on the monad to
provide the sequencing. Isn't it more convenient to use a list of
neurons, as above?

- C.


More information about the Haskell-Cafe mailing list