Preamble
I am trying to wrap my head around how to actually use ContT
and callCC
for something useful. I'm having trouble following information and control flows around the the code. (but, isn't that the point of a continuation?)
There are a lot of different ways to move pieces around with this monad and a small handful of not very straight forward combinators. I will confess that I'm still uncomfortable with my understanding of how ContT works, but I will point to what I have read so far:
What I would like to do is post a psudo-code example then ask some questions about it. This represents the typical look of code using ContT
Psudo-Code
type MyMonad r = ContT r (State SomeState)
main = do
runState s_init $ runContT block print
block :: MyMonad r a0
block = do
before_callcc
output <- callCC $ \k -> do
rval <- inner_block
return rval
after_callcc
Questions
output
?b
mean in the type of k
?k
go?inner_block
run? What version of the state does it see?rval
go and what its type?k
and rval
?k
a) in inner_block
, b) in after_callcc
, c) outside of block
?k
out of block
?k
into the state?Color Coded for easier reading
- What determines the value and type of
output
?
It will be of the same type as rval
. The value will also be the same, unless inner_block
uses k someValue
to escape the rest of the block. In that case, output
will be someValue
.
- What does the
b
mean in the type ofk
?
Roughly, b
can be understood as "anything at all". That is, if inner_block
is
...
v <- k someValue
use v
then v :: b
. However, k someValue
will never run the rest of the block since it will exit the callCC
immediately. So, no concrete value for v
will be ever returned. Because of this v
can have any type: it does not matter if use
requires a String
or an Int
-- it's not being executed anyway.
- Where does the value given to
k
go?
As soon as the inner block runs k someValue
the value is returned by the callCC
as output
, and the rest of the block is skipped.
- When is
inner_block
run? What version of the state does it see?
It is run as callCC
is called, and sees the same state as we had at that point.
- Where does
rval
go and what its type?
Into output
. Same type.
- What is the relationship between
k
andrval
?
rval
has the same type as the argument of k
.
- What happens when I apply
k
a) ininner_block
, b) inafter_callcc
, c) outside ofblock
?
a) See above.
b) k
is out of scope in after_callcc
.
c) Also out of scope.
- What is the version of the state in each of the above?
The state is the "current" one. (I am not sure what you exactly are asking for here)
- What do I need to do to get
k
out ofblock
?
A recursive type is needed here, I guess. Here's an attempt:
import Control.Monad.Cont
import Control.Monad.State
import Control.Monad.Trans
type SomeState = String
type MyMonad r = ContT r (State SomeState)
newtype K a b r = K ((K a b r, a) -> MyMonad r b)
main = do
print $ flip runState "init" $ runContT block return
block :: MyMonad r Int
block = do
lift $ modify (++ ":start")
(K myK, output) <- callCC $ \k -> do
s <- lift $ get
lift $ modify (++ ":inner(" ++ show (length s) ++")")
return (K k, 10)
lift $ modify (++ ":output=" ++ show output)
s <- lift $ get
when (length s <50) $ myK (K myK, output+1)
return 5
This prints
(5,"init:start:inner(10):output=10:output=11:output=12")
- Can I put
k
into the state?
I believe you need a recursive type for that, too.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With