[Haskell-beginners] Learning Monads with 'setjmp' and 'longjmp' like actions

Gesh gesh at gesh.uni.cx
Wed Aug 31 03:03:46 UTC 2016

On 2016-07-24 20:17, Michael Roth wrote:
> Hi,
> I'm really trying hard to understand monads but I guess my brain is 
> trapped in the imperative world.
> Below what I have done so far. But now I would like to implement 
> something like this:
> do
>    foo
>    (label, jumped) <- setjmp
>    bar
>    longjmp label
> But I'm stuck. How can I implement 'setjmp' and 'longjmp' with my monad?
> I'm not able to grasp how can I design 'setjmp' and somehow create a 
> label to use in 'longjmp'.
> Maybe my monad structure is not appropriate?
> Code follows:
> ---------------------------------------------------------------
> data World = SomeWorld
>     deriving (Eq, Show)
> data ProgramResult a =
>     Result      { world :: World, result :: a }
>   | Continue    { world :: World, continue :: Program a }
>   | Stopped     { world :: World }
Firstly, you are correct in noting that `setjmp`/`longjmp` aren't 
implementable in your monad.
Your monad is a variation on the following one:
 > data Lazy a =  Value a | Thunk (() -> Lazy a)
with the obvious instances. In essence, given that your `World` type is 
opaque, I'm treating it as isomorphic to ().
Given that, we have `ProgramResult a ~ Lazy (Maybe a)`.

In contrast, `setjmp`/`longjmp` are *much* more powerful than that.
Any monad in which one can implement them can be used to implement `callCC`.
One can embed the `Cont` monad into such monads (writing the code to do 
this is left as an exercise).
However, one can embed any monad into `Cont`[0], from which it should be 
intuitively obvious that
your monad is not up to the task.

Moreover, usually `setjmp`/`longjmp` is not what you want. Derek Elkins 
explains this much better than I can[1],
but in brief the problem with `setjmp` is that the continuation that it 
corresponds to contains its own use,
which means you need to test whether the current execution of the code 
occurs before the first call to `longjmp`.
The alternative he recommends is `callCC`, which is equivalent in power 
to `setjmp`/`longjmp` but whose usage is simpler.

Hope this helps, despite the original question being over a month old.


[0] - 
[1] - http://lambda-the-ultimate.org/node/3611#comment-51086

P.S. An untested implementation of `setjmp`/`longjmp` in `Cont`:
 > throw :: r -> Cont r b
 > throw e = Cont $ \_ -> e
 > setjmp :: Cont r (Either (a -> Cont r b) a)
 > setjmp = Cont $ \c-> c (Left (throw . c . Right))
 > longjmp :: (a -> Cont r b) -> a -> Cont r b
 > longjmp c v = c v

More information about the Beginners mailing list