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 kdef 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*) -> acont :: (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) -> Intnotice it doesnt matter what outcontis, 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 )) :: Intsince 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) -> acont :: (Int -> b)cont 3 :: Intlambda cont (cont 3) :: (Int -> b) -> Int
3 Continuation return beta
cont x :: b- this means we can apply any operation on
sq(cont x) :: Natstr(cont x) :: Booland 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
ais 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
callback :: A -> B
Eventhandler :: (A -> B) -> A -> K
def Eventhandler(callback,event)
{..callback(event)... }- Eventhandlers are higher order functions that take callbacks