Using the ContT monads for early exits of IO ?

Hi everyone, I'm about to write a rather lengthy piece of IO code. Depending on the results of some of the IO actions I'd like the computation to stop right there and then. Now I know in general how to write this but I'm wondering if this is one of those occasions where I should make use of the Cont monad to make an early exit. Günther

Yeah I don't see why not. The ContT monad should work great.
Also, depending on what you're doing, the ErrorT monad might do what you
want as well.
- Job
2010/6/10 Günther Schmidt
Hi everyone,
I'm about to write a rather lengthy piece of IO code. Depending on the results of some of the IO actions I'd like the computation to stop right there and then.
Now I know in general how to write this but I'm wondering if this is one of those occasions where I should make use of the Cont monad to make an early exit.
Günther
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

I have a general question about this kind of approach. Tutorials on
continuations in Haskell always come with a warning about not using it
unless you have to because it makes code unreadable and
unmaintainable. Is this true in your opinion?
-deech
On 6/10/10, Job Vranish
Yeah I don't see why not. The ContT monad should work great. Also, depending on what you're doing, the ErrorT monad might do what you want as well.
- Job
2010/6/10 Günther Schmidt
Hi everyone,
I'm about to write a rather lengthy piece of IO code. Depending on the results of some of the IO actions I'd like the computation to stop right there and then.
Now I know in general how to write this but I'm wondering if this is one of those occasions where I should make use of the Cont monad to make an early exit.
Günther
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

Günther, This is definitely one way to do it. If you want to be able to "quit" the IO action in the middle of a lengthy computation, that is one way that I, personally, find very straightfoward. You can find an example of this in my Advgame package on Hackage, which uses this method to quit running the main action (although I could have used a conditional to determine whether to continue running the main loop, but continuations are more fun :P). Small example:
foo = (`runContT` id) $ do dummy <- callCC $ \exit -> forever $ do line <- liftIO getLine if line == "quit" then exit $ return () else ... -- do whatever else here...
Cheers,
- Tim
2010/6/10 Günther Schmidt
Hi everyone,
I'm about to write a rather lengthy piece of IO code. Depending on the results of some of the IO actions I'd like the computation to stop right there and then.
Now I know in general how to write this but I'm wondering if this is one of those occasions where I should make use of the Cont monad to make an early exit.
Günther
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

I would not use the continuation monad just for early exit. Sounds
like the error monad to me.
2010/6/10 Günther Schmidt
Hi everyone,
I'm about to write a rather lengthy piece of IO code. Depending on the results of some of the IO actions I'd like the computation to stop right there and then.
Now I know in general how to write this but I'm wondering if this is one of those occasions where I should make use of the Cont monad to make an early exit.
Günther
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

Actually, on second thought, Lennart is probably right. Continuations are
probably overkill for this situation.
Since not wanting to continue is probably an 'erroneous condition,' you may
as well use Error.
Cheers,
- Tim
2010/6/10 Lennart Augustsson
I would not use the continuation monad just for early exit. Sounds like the error monad to me.
2010/6/10 Günther Schmidt
: Hi everyone,
I'm about to write a rather lengthy piece of IO code. Depending on the results of some of the IO actions I'd like the computation to stop right there and then.
Now I know in general how to write this but I'm wondering if this is one of those occasions where I should make use of the Cont monad to make an early exit.
Günther
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

On Thu, 2010-06-10 at 14:09 -0500, Tim Wawrzynczak wrote:
Actually, on second thought, Lennart is probably right. Continuations are probably overkill for this situation. Since not wanting to continue is probably an 'erroneous condition,' you may as well use Error.
Cheers, - Tim
Technically it can be a success. For example if we get a list of HostInfo for given hostname we want to connect once instead of many times. Also the first time might not succeed (it is AAAA entry in IPv4 network). Error monad seems not to be a semantic solution as we exit on success not failure. Regards

Yeah, I might actually prefer calling it EitherT instead of ErrorT. It
doesn't have to be used for error, it's just what it is most often used for.
- Job
On Thu, Jun 10, 2010 at 3:57 PM, Maciej Piechotka
On Thu, 2010-06-10 at 14:09 -0500, Tim Wawrzynczak wrote:
Actually, on second thought, Lennart is probably right. Continuations are probably overkill for this situation. Since not wanting to continue is probably an 'erroneous condition,' you may as well use Error.
Cheers, - Tim
Technically it can be a success. For example if we get a list of HostInfo for given hostname we want to connect once instead of many times. Also the first time might not succeed (it is AAAA entry in IPv4 network).
Error monad seems not to be a semantic solution as we exit on success not failure.
Regards
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

On Thu, Jun 10, 2010 at 8:57 PM, Maciej Piechotka
Error monad seems not to be a semantic solution as we exit on success not failure.
Which is really why the Either monad should not necessarily have Error associations :) If you forget about the fail method, the Monad (Either e) instance doesn't need the e to be an error type. Alternatively, if even Error is more information than you need, you could use MaybeT: http://hackage.haskell.org/package/MaybeT which allows you to just stop. Given you're using it with IO it'd be easy to write a result to an IORef before terminating the computation, so it's of equivalent power, if slightly less convenient.

Or what about a specialized Escape Continuation monad? (Perhaps there is one on hackage, not sure). Something that allows you to set up an continuation (for "escape") purposes, but does not allow you to capture any more continuations after that, and call that escape cont w/in itself, supplying a "return" value. i.e.
run = do result <- createEscape $ \escape -> lengthyComputation1 inp <- askToContinue if (not (continue inp)) then escape "They quit" else lengthyComputation2 return result
Just thinking off the top of my head :).
However, if there are going to be multiple 'lengthy computations' then
perhaps
MaybeT or EitherT would be better, b/c they allow the propagation of failure
across multiple actions, instead of cascading off to the right of the screen
w/ 'if's or 'case's.
Cheers,
- Tim
On Thu, Jun 10, 2010 at 3:21 PM, Ben Millwood
On Thu, Jun 10, 2010 at 8:57 PM, Maciej Piechotka
wrote: Error monad seems not to be a semantic solution as we exit on success not failure.
Which is really why the Either monad should not necessarily have Error associations :) If you forget about the fail method, the Monad (Either e) instance doesn't need the e to be an error type.
Alternatively, if even Error is more information than you need, you could use MaybeT:
http://hackage.haskell.org/package/MaybeT
which allows you to just stop. Given you're using it with IO it'd be easy to write a result to an IORef before terminating the computation, so it's of equivalent power, if slightly less convenient. _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

On Thu, 2010-06-10 at 21:21 +0100, Ben Millwood wrote:
On Thu, Jun 10, 2010 at 8:57 PM, Maciej Piechotka
wrote: Error monad seems not to be a semantic solution as we exit on success not failure.
Which is really why the Either monad should not necessarily have Error associations :) If you forget about the fail method, the Monad (Either e) instance doesn't need the e to be an error type.
Alternatively, if even Error is more information than you need, you could use MaybeT:
http://hackage.haskell.org/package/MaybeT
which allows you to just stop. Given you're using it with IO it'd be easy to write a result to an IORef before terminating the computation, so it's of equivalent power, if slightly less convenient.
Over MaybeT I would prefer to simply iterate over list using helper recursive function. Either monad (without Error part) seems to be good solution - and it do not contain too much information. But the function with ContT IO seemed... nice. Also as it deals with network I/O speed does not seems to be a great issue. Regards

Lennart Augustsson wrote:
I would not use the continuation monad just for early exit. Sounds like the error monad to me.
I.e., the Either/ErrorT monad. But the mtl/transformers packages have an orphan instance for Either that requires the exit type to be an instance of the Error class. If that doesn't work in your case, use the Exit monad: http://www.haskell.org/haskellwiki/New_monads/MonadExit Or use the Maybe monad written additively, i.e. mplus in place of >> (more or less). Regards, Yitz

Or... one could just use the exceptions that are already built into
the IO monad...
2010/6/10 Yitzchak Gale
Lennart Augustsson wrote:
I would not use the continuation monad just for early exit. Sounds like the error monad to me.
I.e., the Either/ErrorT monad. But the mtl/transformers packages have an orphan instance for Either that requires the exit type to be an instance of the Error class. If that doesn't work in your case, use the Exit monad:
http://www.haskell.org/haskellwiki/New_monads/MonadExit
Or use the Maybe monad written additively, i.e. mplus in place of >> (more or less).
Regards, Yitz _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

On Thu, Jun 10, 2010 at 8:45 PM, Derek Elkins
Or... one could just use the exceptions that are already built into the IO monad...
It feels to me like this discussion has a lot of speculation in it. I would like to see concrete examples of the code and the suggested improvements.
2010/6/10 Yitzchak Gale
: Lennart Augustsson wrote:
I would not use the continuation monad just for early exit. Sounds like the error monad to me.
I.e., the Either/ErrorT monad. But the mtl/transformers packages have an orphan instance for Either that requires the exit type to be an instance of the Error class. If that doesn't work in your case, use the Exit monad:
http://www.haskell.org/haskellwiki/New_monads/MonadExit
Or use the Maybe monad written additively, i.e. mplus in place of >> (more or less).
Regards, Yitz _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

2010/6/10 Günther Schmidt
Hi everyone,
I'm about to write a rather lengthy piece of IO code. Depending on the results of some of the IO actions I'd like the computation to stop right there and then.
What's wrong with a mere if/else condition? foo = do bar x <- mu case x of Bar -> return () Mu -> do y <- zot case y of Zot -> return () Foo -> gud foo = do bar x <- mu y <- bar when (pred x y) $ do zot x Continuations are risky for causing confusion of readers (and the author herself), do you definitely need this?

Hi Christopher, there is nothing wrong with ifs as such except the won't actually exit a long piece of code, the computation will continue, just in a useless way. Primarily for every "if" I need two forks, so at every "if" the branches double. I have written the previous code with ifs and it's quite spaghetti-ish and I hope that using callCC here helps to avoid it. Of course there is no guarantee that it actually will. ;) Günther

* Günther Schmidt
there is nothing wrong with ifs as such except the won't actually exit a long piece of code, the computation will continue, just in a useless way.
Can you clarify? -- Roman I. Cheplyaka :: http://ro-che.info/ "Don't let school get in the way of your education." - Mark Twain

On 11 June 2010 10:12, Roman Cheplyaka
* Günther Schmidt
[2010-06-11 01:22:27+0200] there is nothing wrong with ifs as such except the won't actually exit a long piece of code, the computation will continue, just in a useless way.
Can you clarify?
I think Günther assumed that I was suggesting:
do if x
then return ()
else bar
continueComputation
The problem is that if 'x' is true, continueComputation should
never happen. So you can solve it like this, which is what I was
actually suggesting:
do if x
then return ()
else do bar; continueComputation
But then you have this problem, which Günther addressed:
2010/6/11 Günther Schmidt
Primarily for every "if" I need two forks, so at every "if" the branches double.
Which can be a big problem if you have a sequence of heterogenous actions that must be executed in order and are dependant and nested. Continutations solve this, as do ErrorT and MaybeT which are both restricted subsets for returning values. I'd use MaybeT if a value needed to be returned, or nothing.

Hello Christopher, Friday, June 11, 2010, 4:06:05 PM, you wrote:
do if x then return () else do bar; continueComputation
i format it this way: if x then return () else do bar continueComputation -- Best regards, Bulat mailto:Bulat.Ziganshin@gmail.com

On 11 June 2010 14:27, Bulat Ziganshin
i format it this way:
if x then return () else do bar continueComputation
That's a nice way of formatting! God bless optional formatting! I like this problem-specific indentation. Another is: if x then foo else if y then bar else if z then mu else zot Kind of similar to a COND statement from Lisp.

Hello Christopher, Friday, June 11, 2010, 4:35:00 PM, you wrote:
if x then foo else if y then bar else if z then mu else zot
case () of _ | x -> foo | y -> bar | otherwise -> zor it's usually considered as "haskell way" of doing this -- Best regards, Bulat mailto:Bulat.Ziganshin@gmail.com

On 11 June 2010 14:40, Bulat Ziganshin
if x then foo else if y then bar else if z then mu else zot
case () of _ | x -> foo | y -> bar | otherwise -> zor
it's usually considered as "haskell way" of doing this
The example is merely to demonstrate how optional layout can encode useful patterns, not to claim there aren't other ways to do it in Haskell. For what it's worth, this solution is pretty hackish and so not really Haskelly.

Hello Günther,
I use ContT monads for early exit often, because that's one of the
things they encode naturally. But I don't do this with callCC. I
prefer monadLib over mtl/transformers, which has a specific function for
that:
abort :: (AbortM m i) => i -> m a
where AbortM is a class for monads, whose computations are abortable.
All ContT monads are instances. This is also a nice way to break out of
'forever'.
Using an error monad (like Maybe) may be more natural of course.
Greets,
Ertugrul
Günther Schmidt
Hi everyone,
I'm about to write a rather lengthy piece of IO code. Depending on the results of some of the IO actions I'd like the computation to stop right there and then.
Now I know in general how to write this but I'm wondering if this is one of those occasions where I should make use of the Cont monad to make an early exit.
Günther
-- nightmare = unsafePerformIO (getWrongWife >>= sex) http://blog.ertes.de/
participants (14)
-
aditya siram
-
Ben Millwood
-
Bulat Ziganshin
-
Christopher Done
-
Derek Elkins
-
Ertugrul Soeylemez
-
Günther Schmidt
-
Jason Dagit
-
Job Vranish
-
Lennart Augustsson
-
Maciej Piechotka
-
Roman Cheplyaka
-
Tim Wawrzynczak
-
Yitzchak Gale