SLIDE 1 Effect handler oriented programming
Sam Lindley
The University of Edinburgh and Imperial College London
18th February 2020
SLIDE 2
Part I Prologue
SLIDE 3 L i n k s
http://www.links-lang.org
Database Integration Concurrency & Distribution Effect Handlers WeB Development Interactive Programming
L i n k i n g t h e
y t
r a c t i c e f
t h e w e b
Q u e r y S h r e d d i n g L a n g u a g e
n t e g r a t e d Q u e r y P r
e n a n c e R e l a t i
a l L e n s e s T y p e d H T ML + a n t i q u
e s F
ml e t s Mo d e l
i e w
p d a t e C P S T r a n s l a t i
( C l i e n t ) R
a s e d E fg e c t s C E K Ma c h i n e ( S e r v e r ) R P C C a l c u l u s S e s s i
E x c e p t i
s
D i s t r i b u t e d S e s s i
T y p e s
T r y L i n k s
N
e b
P r
r a mmi n g
Wi t h t h a n k s t
i m
F
l e r
SLIDE 4
Part II Effect handler oriented programming
SLIDE 5
Effects
Programs as black boxes (Church-Turing model)?
SLIDE 6
Effects
Programs must interact with their environment
SLIDE 7
Effects
Programs must interact with their environment Effects are pervasive ◮ input/output user interaction ◮ concurrency web applications ◮ distribution cloud computing ◮ exceptions fault tolerance ◮ choice backtracking search
SLIDE 8
Effects
Programs must interact with their environment Effects are pervasive ◮ input/output user interaction ◮ concurrency web applications ◮ distribution cloud computing ◮ exceptions fault tolerance ◮ choice backtracking search Typically ad hoc and hard-wired
SLIDE 9
Effect handlers
Deep theory
Gordon Plotkin Matija Pretnar Handlers of algebraic effects, ESOP 2009
SLIDE 10
Effect handlers
Deep theory
Gordon Plotkin Matija Pretnar Handlers of algebraic effects, ESOP 2009 Composable and user-defined interpretation of effects in general
SLIDE 11
Effect handlers
Deep theory
Gordon Plotkin Matija Pretnar Handlers of algebraic effects, ESOP 2009 Composable and user-defined interpretation of effects in general Give programmer direct access to environment (c.f. resumable exceptions, monads, delimited control)
SLIDE 12
Effect handlers
Deep theory
Gordon Plotkin Matija Pretnar Handlers of algebraic effects, ESOP 2009 Composable and user-defined interpretation of effects in general Give programmer direct access to environment (c.f. resumable exceptions, monads, delimited control) Growing industrial interest React JavaScript UI library (used by > 1 million websites) Pyro Probabilistic programming language (statistical inference) Semantic Code analysis library (> 4.5 million Python repositories)
SLIDE 13
Example 1: choice and failure
Effect signature
{choose : 1 ⇒ Bool, fail : a.1 ⇒ a}
SLIDE 14
Example 1: choice and failure
Effect signature
{choose : 1 ⇒ Bool, fail : a.1 ⇒ a}
Drunk coin tossing
toss () = if choose () then Heads else Tails drunkToss () = if choose () then if choose () then Heads else Tails else fail () drunkTosses n = if n = 0 then [] else drunkToss () :: drunkTosses (n − 1)
SLIDE 15
Example 1: choice and failure
Handlers
maybeFail = — exception handler return x → Just x fail () → Nothing
SLIDE 16
Example 1: choice and failure
Handlers
maybeFail = — exception handler return x → Just x fail () → Nothing handle 42 with maybeFail = ⇒ Just 42 handle fail () with maybeFail = ⇒ Nothing
SLIDE 17
Example 1: choice and failure
Handlers
maybeFail = — exception handler return x → Just x fail () → Nothing handle 42 with maybeFail = ⇒ Just 42 handle fail () with maybeFail = ⇒ Nothing trueChoice = — linear handler return x → x choose () → r → r True
SLIDE 18
Example 1: choice and failure
Handlers
maybeFail = — exception handler return x → Just x fail () → Nothing handle 42 with maybeFail = ⇒ Just 42 handle fail () with maybeFail = ⇒ Nothing trueChoice = — linear handler return x → x choose () → r → r True handle 42 with trueChoice = ⇒ 42 handle toss () with trueChoice = ⇒ Heads
SLIDE 19
Example 1: choice and failure
Handlers
maybeFail = — exception handler return x → Just x fail () → Nothing handle 42 with maybeFail = ⇒ Just 42 handle fail () with maybeFail = ⇒ Nothing trueChoice = — linear handler return x → x choose () → r → r True handle 42 with trueChoice = ⇒ 42 handle toss () with trueChoice = ⇒ Heads allChoices = — non-linear handler return x → [x] choose () → r → r True + + r False
SLIDE 20
Example 1: choice and failure
Handlers
maybeFail = — exception handler return x → Just x fail () → Nothing handle 42 with maybeFail = ⇒ Just 42 handle fail () with maybeFail = ⇒ Nothing trueChoice = — linear handler return x → x choose () → r → r True handle 42 with trueChoice = ⇒ 42 handle toss () with trueChoice = ⇒ Heads allChoices = — non-linear handler return x → [x] choose () → r → r True + + r False handle 42 with allChoices = ⇒ [42] handle toss () with allChoices = ⇒ [Heads, Tails]
SLIDE 21
Example 1: choice and failure
Handlers
maybeFail = — exception handler return x → Just x fail () → Nothing handle 42 with maybeFail = ⇒ Just 42 handle fail () with maybeFail = ⇒ Nothing trueChoice = — linear handler return x → x choose () → r → r True handle 42 with trueChoice = ⇒ 42 handle toss () with trueChoice = ⇒ Heads allChoices = — non-linear handler return x → [x] choose () → r → r True + + r False handle 42 with allChoices = ⇒ [42] handle toss () with allChoices = ⇒ [Heads, Tails] handle (handle drunkTosses 2 with maybeFail) with allChoices = ⇒
SLIDE 22
Example 1: choice and failure
Handlers
maybeFail = — exception handler return x → Just x fail () → Nothing handle 42 with maybeFail = ⇒ Just 42 handle fail () with maybeFail = ⇒ Nothing trueChoice = — linear handler return x → x choose () → r → r True handle 42 with trueChoice = ⇒ 42 handle toss () with trueChoice = ⇒ Heads allChoices = — non-linear handler return x → [x] choose () → r → r True + + r False handle 42 with allChoices = ⇒ [42] handle toss () with allChoices = ⇒ [Heads, Tails] handle (handle drunkTosses 2 with maybeFail) with allChoices = ⇒ [Just [Heads, Heads], Just [Heads, Tails], Nothing, Just [Tails, Heads], Just [Tails, Tails], Nothing, Nothing]
SLIDE 23
Example 1: choice and failure
Handlers
maybeFail = — exception handler return x → Just x fail () → Nothing handle 42 with maybeFail = ⇒ Just 42 handle fail () with maybeFail = ⇒ Nothing trueChoice = — linear handler return x → x choose () → r → r True handle 42 with trueChoice = ⇒ 42 handle toss () with trueChoice = ⇒ Heads allChoices = — non-linear handler return x → [x] choose () → r → r True + + r False handle 42 with allChoices = ⇒ [42] handle toss () with allChoices = ⇒ [Heads, Tails] handle (handle drunkTosses 2 with maybeFail) with allChoices = ⇒ [Just [Heads, Heads], Just [Heads, Tails], Nothing, Just [Tails, Heads], Just [Tails, Tails], Nothing, Nothing] handle (handle drunkTosses 2 with allChoices) with maybeFail = ⇒
SLIDE 24
Example 1: choice and failure
Handlers
maybeFail = — exception handler return x → Just x fail () → Nothing handle 42 with maybeFail = ⇒ Just 42 handle fail () with maybeFail = ⇒ Nothing trueChoice = — linear handler return x → x choose () → r → r True handle 42 with trueChoice = ⇒ 42 handle toss () with trueChoice = ⇒ Heads allChoices = — non-linear handler return x → [x] choose () → r → r True + + r False handle 42 with allChoices = ⇒ [42] handle toss () with allChoices = ⇒ [Heads, Tails] handle (handle drunkTosses 2 with maybeFail) with allChoices = ⇒ [Just [Heads, Heads], Just [Heads, Tails], Nothing, Just [Tails, Heads], Just [Tails, Tails], Nothing, Nothing] handle (handle drunkTosses 2 with allChoices) with maybeFail = ⇒ Nothing
SLIDE 25 Small-step operational semantics for (deep) effect handlers
Reduction rules
let x = V in N N[V /x] handle V with H Nret[V /x] handle E[op V ] with H Nop[V /p, (λx.handle E[x] with H)/r],
where H = return x → Nret
· · ·
Evaluation contexts
E ::= [ ] | let x = E in N | handle E with H
SLIDE 26
Example 2: cooperative concurrency (static)
Effect signature
{yield : 1 ⇒ 1}
SLIDE 27
Example 2: cooperative concurrency (static)
Effect signature
{yield : 1 ⇒ 1}
Two cooperative lightweight threads
tA () = print (“A1 ”); yield (); print (“A2 ”) tB () = print (“B1 ”); yield (); print (“B2 ”)
SLIDE 28
Example 2: cooperative concurrency (static)
Effect signature
{yield : 1 ⇒ 1}
Two cooperative lightweight threads
tA () = print (“A1 ”); yield (); print (“A2 ”) tB () = print (“B1 ”); yield (); print (“B2 ”)
Handler
— parameterised handler coop ([]) = return () → () yield () → r′ → r′ [] () coop (r :: rs) = return () → r rs () yield () → r′ → r (rs + + [r′]) ()
SLIDE 29
Example 2: cooperative concurrency (static)
Effect signature
{yield : 1 ⇒ 1}
Two cooperative lightweight threads
tA () = print (“A1 ”); yield (); print (“A2 ”) tB () = print (“B1 ”); yield (); print (“B2 ”)
Handler
— parameterised handler coop ([]) = return () → () yield () → r′ → r′ [] () coop (r :: rs) = return () → r rs () yield () → r′ → r (rs + + [r′]) ()
Helpers
coopWith t rs () = handle t () with coop rs cooperate ts = coopWith id (map coopWith ts) ()
SLIDE 30
Example 2: cooperative concurrency (static)
Effect signature
{yield : 1 ⇒ 1}
Two cooperative lightweight threads
tA () = print (“A1 ”); yield (); print (“A2 ”) tB () = print (“B1 ”); yield (); print (“B2 ”)
Handler
— parameterised handler coop ([]) = return () → () yield () → r′ → r′ [] () coop (r :: rs) = return () → r rs () yield () → r′ → r (rs + + [r′]) ()
Helpers
coopWith t rs () = handle t () with coop rs cooperate ts = coopWith id (map coopWith ts) () cooperate [tA, tB] = ⇒ () A1 B1 A2 B2
SLIDE 31 Small-step operational semantics for parameterised effect handlers
Reduction rules
let x = V in N N[V /x] handle V with H W Nret[V /x, W /h] handle E[op V ] with H W Nop[V /p, W /h, (λh x.handle E[x] with H h)/r],
where H h = return x → Nret
· · ·
Evaluation contexts
E ::= [ ] | let x = E in N | handle E with H W
SLIDE 32 Small-step operational semantics for parameterised effect handlers
Reduction rules
let x = V in N N[V /x] handle V with H W Nret[V /x, W /h] handle E[op V ] with H W Nop[V /p, W /h, (λh x.handle E[x] with H h)/r],
where H h = return x → Nret
· · ·
Evaluation contexts
E ::= [ ] | let x = E in N | handle E with H W Exercise: express parameterised handlers as non-parameterised handlers
SLIDE 33
Example 3: cooperative concurrency (dynamic)
Effect signature
— recursive effect signature Co = {yield : 1 ⇒ 1, fork : (1 → [Co]1) ⇒ 1}
SLIDE 34
Example 3: cooperative concurrency (dynamic)
Effect signature
— recursive effect signature Co = {yield : 1 ⇒ 1, fork : (1 → [Co]1) ⇒ 1}
A single cooperative program
main () = print “M1 ”; fork (λ().print “A1 ”; yield (); print “A2 ”); print “M2 ”; fork (λ().print “B1 ”; yield (); print “B2 ”); print “M3 ”
SLIDE 35
Example 3: cooperative concurrency (dynamic)
Effect signature
— recursive effect signature Co = {yield : 1 ⇒ 1, fork : (1 → [Co]1) ⇒ 1}
A single cooperative program
main () = print “M1 ”; fork (λ().print “A1 ”; yield (); print “A2 ”); print “M2 ”; fork (λ().print “B1 ”; yield (); print “B2 ”); print “M3 ”
Parameterised handler and helpers
coop ([]) = return () → () yield () → r′ → r′ [] () fork t → r′ → coopWith t [r′] () coop (r :: rs) = return () → r rs () yield () → r′ → r (rs + + [r′]) () fork t → r′ → coopWith t (r :: rs + + [r′]) () coopWith t rs () = handle t () with coop rs cooperate ts = coopWith id (map coopWith ts) ()
SLIDE 36
Example 3: cooperative concurrency (dynamic)
Effect signature
— recursive effect signature Co = {yield : 1 ⇒ 1, fork : (1 → [Co]1) ⇒ 1}
A single cooperative program
main () = print “M1 ”; fork (λ().print “A1 ”; yield (); print “A2 ”); print “M2 ”; fork (λ().print “B1 ”; yield (); print “B2 ”); print “M3 ”
Parameterised handler and helpers
coop ([]) = return () → () yield () → r′ → r′ [] () fork t → r′ → coopWith t [r′] () coop (r :: rs) = return () → r rs () yield () → r′ → r (rs + + [r′]) () fork t → r′ → coopWith t (r :: rs + + [r′]) () coopWith t rs () = handle t () with coop rs cooperate ts = coopWith id (map coopWith ts) () cooperate [main] = ⇒ () M1 A1 M2 B1 A2 M3 B2
SLIDE 37
Example 3: cooperative concurrency (dynamic)
Effect signature
— recursive effect signature Co = {yield : 1 ⇒ 1, fork : (1 → [Co]1) ⇒ 1}
A single cooperative program
main () = print “M1 ”; fork (λ().print “A1 ”; yield (); print “A2 ”); print “M2 ”; fork (λ().print “B1 ”; yield (); print “B2 ”); print “M3 ”
Parameterised handler and helpers
coop ([]) = return () → () yield () → r′ → r′ [] () fork t → r′ → r′ [coopWith t] () coop (r :: rs) = return () → r rs () yield () → r′ → r (rs + + [r′]) () fork t → r′ → r′ (r :: rs + + [coopWith t]) () coopWith t rs () = handle t () with coop rs cooperate ts = coopWith id (map coopWith ts) ()
SLIDE 38
Example 3: cooperative concurrency (dynamic)
Effect signature
— recursive effect signature Co = {yield : 1 ⇒ 1, fork : (1 → [Co]1) ⇒ 1}
A single cooperative program
main () = print “M1 ”; fork (λ().print “A1 ”; yield (); print “A2 ”); print “M2 ”; fork (λ().print “B1 ”; yield (); print “B2 ”); print “M3 ”
Parameterised handler and helpers
coop ([]) = return () → () yield () → r′ → r′ [] () fork t → r′ → r′ [coopWith t] () coop (r :: rs) = return () → r rs () yield () → r′ → r (rs + + [r′]) () fork t → r′ → r′ (r :: rs + + [coopWith t]) () coopWith t rs () = handle t () with coop rs cooperate ts = coopWith id (map coopWith ts) () cooperate [main] = ⇒ () M1 M2 M3 A1 B1 A2 B2
SLIDE 39
Example 4: pipes
Effect signatures
Sender = {send : Nat ⇒ 1} Receiver = {receive : 1 ⇒ Nat}
SLIDE 40
Example 4: pipes
Effect signatures
Sender = {send : Nat ⇒ 1} Receiver = {receive : 1 ⇒ Nat}
A producer and a consumer
nats n = send n; nats (n + 1) grabANat () = receive ()
SLIDE 41
Example 4: pipes
Effect signatures
Sender = {send : Nat ⇒ 1} Receiver = {receive : 1 ⇒ Nat}
A producer and a consumer
nats n = send n; nats (n + 1) grabANat () = receive ()
Pipes and copipes as shallow handlers
pipe p c = handle† c () with return x → x receive () → r → copipe r p copipe c p = handle† p () with return x → x send n → r → pipe r (λ().c n)
SLIDE 42
Example 4: pipes
Effect signatures
Sender = {send : Nat ⇒ 1} Receiver = {receive : 1 ⇒ Nat}
A producer and a consumer
nats n = send n; nats (n + 1) grabANat () = receive ()
Pipes and copipes as shallow handlers
pipe p c = handle† c () with return x → x receive () → r → copipe r p copipe c p = handle† p () with return x → x send n → r → pipe r (λ().c n) pipe (λ().nats 0) grabANat + copipe (λx.x) (λ().nats 0) + pipe (λ().nats 1) (λ().0) + 0
SLIDE 43
Example 4: pipes
Effect signatures
Sender = {send : Nat ⇒ 1} Receiver = {receive : 1 ⇒ Nat}
A producer and a consumer
nats n = send n; nats (n + 1) grabANat () = receive ()
Pipes and copipes as shallow handlers
pipe p c = handle† c () with return x → x receive () → r → copipe r p copipe c p = handle† p () with return x → x send n → r → pipe r (λ().c n) pipe (λ().nats 0) grabANat + copipe (λx.x) (λ().nats 0) + pipe (λ().nats 1) (λ().0) + 0 Exercise: implement pipes using deep handlers
SLIDE 44 Small-step operational semantics for shallow effect handlers
Reduction rules
let x = V in N N[V /x] handle† V with H Nret[V /x] handle† E[op V ] with H Nop[V /p, (λx.E[x])/r],
where H = return x → Nret
· · ·
Evaluation contexts
E ::= [ ] | let x = E in N | handle† E with H
SLIDE 45 Small-step operational semantics for shallow effect handlers
Reduction rules
let x = V in N N[V /x] handle† V with H Nret[V /x] handle† E[op V ] with H Nop[V /p, (λx.E[x])/r],
where H = return x → Nret
· · ·
Evaluation contexts
E ::= [ ] | let x = E in N | handle† E with H Exercise: express shallow handlers as deep handlers
SLIDE 46 Built-in effects
Console I/O
Console = {inch : 1 ⇒ char
print s = map (λc.ouch c) s; ()
State
State = {new : a. a ⇒ Ref a, write : a. (Ref a × a) ⇒ 1, read : a. Ref a ⇒ a}
SLIDE 47
Example 5: actors
Process ids
Pid a = Ref (List a)
Effect signature
Actor a = {self : 1 ⇒ Pid a, spawn : b. (1 → [Actor b]1) ⇒ Pid b, send : b. (b × Pid b) ⇒ 1, recv : 1 ⇒ a}
SLIDE 48
Example 5: actors
Process ids
Pid a = Ref (List a)
Effect signature
Actor a = {self : 1 ⇒ Pid a, spawn : b. (1 → [Actor b]1) ⇒ Pid b, send : b. (b × Pid b) ⇒ 1, recv : 1 ⇒ a}
An actor chain
spawnMany p 0 = send (“ping!”, p) spawnMany p n = spawnMany (spawn (λ().let s = recv () in print “.”; send (s, p))) (n − 1) chain n = spawnMany (self ()) n; let s = recv () in print s
SLIDE 49
Example 5: actors
Actors via cooperative concurrency
act mine = return () → () self () → r → r mine mine spawn you → r → let yours = new [] in fork (λ().act yours (you ())); r mine yours send (m, yours) → r → let ms = read yours in write (yours, ms + + [m]); r mine () recv () → r → case read mine of [] → yield (); r mine (recv ()) (m :: ms) → write (mine, ms); r mine m
SLIDE 50
Example 5: actors
Actors via cooperative concurrency
act mine = return () → () self () → r → r mine mine spawn you → r → let yours = new [] in fork (λ().act yours (you ())); r mine yours send (m, yours) → r → let ms = read yours in write (yours, ms + + [m]); r mine () recv () → r → case read mine of [] → yield (); r mine (recv ()) (m :: ms) → write (mine, ms); r mine m cooperate [handle chain 64 with act (new [])] = ⇒ () ................................................................ping!
SLIDE 51
Effect handler oriented programming languages
Eff https://www.eff-lang.org/ Frank https://github.com/frank-lang/frank Helium https://bitbucket.org/pl-uwr/helium Links https://www.links-lang.org/ Koka https://github.com/koka-lang/koka Multicore OCaml https://github.com/ocamllabs/ocaml-multicore/wiki
SLIDE 52 Effect handlers — some of my contributions
Handlers in action (ICFP 2013) with Kammar and Oury Effect handlers in Links (TyDe 2016 / JFP 2020) with Hillerstr¨
Frank programming language (POPL 2017 / JFP 2020) with Convent, McBride, and McLaughlin Expressive power of effect handlers (ICFP 2017 / JFP 2019) with Forster, Kammar, and Pretnar Continuation-passing style for effect handlers (FSCD 2017 / JFP 2020) with Atkey, Hillerstr¨
Shallow effect handlers (APLAS 2018 / JFP 2020) with Hillerstr¨
Linear effect handlers for session exceptions (POPL 2019) with Decova, Fowler, and Morris
SLIDE 53
Scalability challenges
Modularity — effect typing
◮ Effect encapsulation ◮ Linearity ◮ Generativity ◮ Indexed effects ◮ Equations
Efficiency — compilation techniques
◮ Segmented stacks (Multicore OCaml / C library) ◮ Continuation Passing Style (JavaScript backends) ◮ Fusion (Haskell libraries / Eff) ◮ Staging (Scala Effekt library)
SLIDE 54
New directions
Effect handlers for Wasm add effect handlers once and for all — avoid pitfalls of JavaScript Asynchronous effects pre-emptive concurrency; reactive programming Gradually typed effect handlers transition mainstream languages towards effect typing Hardware capabilities as dynamic effects safe effect handlers in C? efficient implementation? Lexically scoped effect handlers improved hygiene? improved performance? improved reasoning?
SLIDE 55
Resources
Jeremy Yallop’s effects bibliography https://github.com/yallop/effects-bibliography Matija Pretnar’s tutorial “An introduction to algebraic effects and handlers”, MFPS 2015 Andrej Bauer’s tutorial “What is algebraic about algebraic effects and handlers?”, Dagstuhl and OPLSS 2018
SLIDE 56
Part III Bonus slides
SLIDE 57
Example 6: effect pollution
Effect signatures
Receiver = {receive : 1 ⇒ Nat} Failure = {fail : a.1 ⇒ a}
SLIDE 58
Example 6: effect pollution
Effect signatures
Receiver = {receive : 1 ⇒ Nat} Failure = {fail : a.1 ⇒ a}
Handlers
receives ([]) = return x → x receive () → r → fail () receives (n :: ns) = return x → x receive () → r → r ns n maybeFail = return x → Just x fail () → r → Nothing
SLIDE 59
Example 6: effect pollution
Effect signatures
Receiver = {receive : 1 ⇒ Nat} Failure = {fail : a.1 ⇒ a}
Handlers
receives ([]) = return x → x receive () → r → fail () receives (n :: ns) = return x → x receive () → r → r ns n maybeFail = return x → Just x fail () → r → Nothing bad ns t = handle (handle t () with receives ns) with maybeFail
SLIDE 60
Example 6: effect pollution
Effect signatures
Receiver = {receive : 1 ⇒ Nat} Failure = {fail : a.1 ⇒ a}
Handlers
receives ([]) = return x → x receive () → r → fail () receives (n :: ns) = return x → x receive () → r → r ns n maybeFail = return x → Just x fail () → r → Nothing bad ns t = handle (handle t () with receives ns) with maybeFail bad [1, 2] (λ().receive () + fail ()) = ⇒ Nothing
SLIDE 61
Example 7: counting
Predicates as higher order functions
Pred = (Nat → Bool) → Bool
Signature of a counting function
count : ((Nat → Bool) → Bool) → Nat
Exclusive or
count (λv.if v 0 then not (v 1) else v 1) = 2
SLIDE 62 Example 7: counting
Counting with a choice handler
count : ((Nat → Bool) → Bool) → Nat count = λp.handle p (λ .choose ()) with return x → if x then 1 else 0 choose () → r → r True + r False
Exclusive or
count (λv.if v 0 then not (v 1) else v 1)
?0 ?1 !False !True ?1 !True !False
SLIDE 63 Example 7: counting
Counting with a choice handler
count : ((Nat → Bool) → Bool) → Nat count = λp.handle p (λ .choose ()) with return x → if x then 1 else 0 choose () → r → r True + r False
Exclusive or
count (λv.if v 0 then not (v 1) else v 1)
?0 ?1 !False !True ?1 !True !False
SLIDE 64 Example 7: counting
Counting with a choice handler
count : ((Nat → Bool) → Bool) → Nat count = λp.handle p (λ .choose ()) with return x → if x then 1 else 0 choose () → r → r True + r False
Exclusive or
count (λv.if v 0 then not (v 1) else v 1)
?0 ?1 !False !True ?1 !True !False
SLIDE 65 Example 7: counting
Counting with a choice handler
count : ((Nat → Bool) → Bool) → Nat count = λp.handle p (λ .choose ()) with return x → if x then 1 else 0 choose () → r → r True + r False
Exclusive or
count (λv.if v 0 then not (v 1) else v 1)
?0 ?1 !False !True ?1 !True !False
SLIDE 66 Example 7: counting
Counting with a choice handler
count : ((Nat → Bool) → Bool) → Nat count = λp.handle p (λ .choose ()) with return x → if x then 1 else 0 choose () → r → r True + r False
Exclusive or
count (λv.if v 0 then not (v 1) else v 1)
?0 ?1 !False !True ?1 !True !False
SLIDE 67 Example 7: counting
Counting with a choice handler
count : ((Nat → Bool) → Bool) → Nat count = λp.handle p (λ .choose ()) with return x → if x then 1 else 0 choose () → r → r True + r False
Exclusive or
count (λv.if v 0 then not (v 1) else v 1)
?0 ?1 !False !True ?1 !True !False
SLIDE 68 Example 7: counting
Counting with a choice handler
count : ((Nat → Bool) → Bool) → Nat count = λp.handle p (λ .choose ()) with return x → if x then 1 else 0 choose () → r → r True + r False
Exclusive or
count (λv.if v 0 then not (v 1) else v 1)
?0 ?1 !False !True ?1 !True !False
SLIDE 69 Example 7: counting
Counting with a choice handler
count : ((Nat → Bool) → Bool) → Nat count = λp.handle p (λ .choose ()) with return x → if x then 1 else 0 choose () → r → r True + r False
Exclusive or
count (λv.if v 0 then not (v 1) else v 1)
?0 ?1 !False !True ?1 !True !False
SLIDE 70 Example 7: counting
Counting with a choice handler
count : ((Nat → Bool) → Bool) → Nat count = λp.handle p (λ .choose ()) with return x → if x then 1 else 0 choose () → r → r True + r False
Exclusive or
count (λv.if v 0 then not (v 1) else v 1)
?0 ?1 !False !True ?1 !True !False
SLIDE 71 Example 7: counting
Counting with a choice handler
count : ((Nat → Bool) → Bool) → Nat count = λp.handle p (λ .choose ()) with return x → if x then 1 else 0 choose () → r → r True + r False
Exclusive or
count (λv.if v 0 then not (v 1) else v 1)
?0 ?1 !False !True ?1 !True !False
SLIDE 72 Example 7: counting
Counting with a choice handler
count : ((Nat → Bool) → Bool) → Nat count = λp.handle p (λ .choose ()) with return x → if x then 1 else 0 choose () → r → r True + r False
Exclusive or
count (λv.if v 0 then not (v 1) else v 1)
?0 ?1 !False !True ?1 !True !False
SLIDE 73 Example 7: counting
Counting with a choice handler
count : ((Nat → Bool) → Bool) → Nat count = λp.handle p (λ .choose ()) with return x → if x then 1 else 0 choose () → r → r True + r False
Exclusive or
count (λv.if v 0 then not (v 1) else v 1)
?0 ?1 !False !True ?1 !True !False
SLIDE 74 Example 7: counting
Counting with a choice handler
count : ((Nat → Bool) → Bool) → Nat count = λp.handle p (λ .choose ()) with return x → if x then 1 else 0 choose () → r → r True + r False
Exclusive or
count (λv.if v 0 then not (v 1) else v 1)
?0 ?1 !False !True ?1 !True !False
SLIDE 75 Example 7: counting
Counting with a choice handler
count : ((Nat → Bool) → Bool) → Nat count = λp.handle p (λ .choose ()) with return x → if x then 1 else 0 choose () → r → r True + r False
Exclusive or
count (λv.if v 0 then not (v 1) else v 1)
?0 ?1 !False !True ?1 !True !False
SLIDE 76 Example 7: counting
Counting with a choice handler
count : ((Nat → Bool) → Bool) → Nat count = λp.handle p (λ .choose ()) with return x → if x then 1 else 0 choose () → r → r True + r False
Exclusive or
count (λv.if v 0 then not (v 1) else v 1)
?0 ?1 !False !True ?1 !True !False