Visualize Callcc
Posted on September 2, 2022
Tags: typetheory
1 visualize continuations
plusk
/ \ \
2 5 k+----+ |
| |
plus(2,5) |
| |
o------o
plus(2,5) is piped into k
def plusk(a,b,k):
k(a+b)
def mulk(a,b,k):
k(a*b)
plusk(2,5, λT.mulk(T,7,print))
# 2+5=7 is placed into λT
In typical cps, the continuations are nested into the 3rd argument
Notice similarity to js except instead of nested, we can move it out into a thennable
plus(2,5).then(T => mult(T,7)).then(o => console.log(o))
plusk
/ \ \
2 5 λT.mulk+--&--+ / \ \
| T 7 print
| | | |
plus(2,5) | | |
| | | |
o--#--o | |
| | |
| | |
T:=plus(2,5) | |
+----&--+ |
| |
mul(plus(2,5),7) |
| |
o----#----o
+--&--+ stands for unwrap, ex: unwrap plusk to plus
o--#--o stands for pipe, ex: pipe plus(2,5) into λK
- plusk is unwrapped to plus and @ to (2,5) RESULT: plus(2,5)
- continuation of plusk, λK.mulk(a,7,print) is @ to plus(2,5) RESULT: mulk(7,7,print)
- mulk is unwrapped to mul and @ to (7,7) RESULT: mul(7,7)
- continuation of mulk, print is @ to mul(7,7)
The continuation k is applied @ to (2,5)
1.1 Example 2
- Notice all the action is being done in the argument of the function.
def Negk(a,k):
k(-a)
Negk(3,λa.Negk(a,λb.Negk(b,return)))
#same as above but formatted differently
Negk(3,
λa.Negk(a,
λb.Negk(b,return)
)
)
2 Investigating callcc
((a ->b) -> a*) -> a
cont :: (a ->b)
the power of having the continuation as a function or as the bound lambda variable is that we don’t actually have to use the continuation.lambda cont. 3 :: (a -> b) -> Int
notice it doesnt matter what outcont
is, we just return 3 regardless
a*
can be considered the hole to be filled. in2 + callcc...
, the hole of the2 + []
is an Int.
+
/ \
2 @/ \
callcc lambda cont.|
@
/ \
cont 3
(+2 (callcc (lambda (cont) 3 )))
> 5
- in the above case we never used the continuation
(lambda (cont) 3 ) :: ? -> ?
callcc :: (?-> ?) -> Int
- note that
(? -> ?)
can also be((? -> ?) -> ?)
- note that
(callcc (lambda (cont) 3 )) :: Int
since we know this expr return 3 for the output to be 5
(+ 2 (callcc (lambda cont (cont 3) 6 )))
(+ 2 3)
callcc :: ((a -> b) -> a) -> a
cont :: (Int -> b)
cont 3 :: Int
lambda cont (cont 3) :: (Int -> b) -> Int
3 Continuation return beta
cont x :: b
- this means we can apply any operation on
sq(cont x) :: Nat
str(cont x) :: Bool
and the type can be anything but since continuation is like an early return, it doesn’t do anything meaningful but change the type.
- this means we can apply any operation on
4 The only type that really matters it the first a
callcc :: ((a ...
- The first
a
is basically the save point and it determines the third and fortha
.
- The first
5 Eventhandlers and Callback functions
- Whenever you hear Evenhandler, think higher order function
- Whenever you hear Callback, think there must exist a higher order function that calls the Callback
event :: A-> B
callback :: A -> B) -> A -> K
Eventhandler :: (A
def Eventhandler(callback,event)
{..callback(event)... }
- Eventhandlers are higher order functions that take callbacks