3. Algebraic effects & handlers
[Plotkin & Pretnar ’09, ’13]
• A mechanism to give user-defined effects
(a.k.a. to use continuations in a “well-structured” manner)
• Separating interfaces and implementations
of effects
• Invoked via operations
• Interpreted by handlers
• Handlers give the ability to call continuations
• Implemented as libraries or primitives in
languages such as Eff, Koka, Frank, etc.
!3
4. Example
effect fail : str ! unit
let div (x:int) (y:int) =
if y = 0 then (#fail “div0”; -1)
else x / y
let f (x:int) : (str,int) either =
handle (div 42 x) with
return (y:int) ! Right y
fail (y:str) ! Left y
!4
5. Example
effect fail : str ! unit
let div (x:int) (y:int) =
if y = 0 then (#fail “div0”; -1)
else x / y
let f (x:int) : (str,int) either =
handle (div 42 x) with
return (y:int) ! Right y
fail (y:str) ! Left y
Declare fail operation
!5
6. Example
effect fail : str ! unit
let div (x:int) (y:int) =
if y = 0 then (#fail “div0”; -1)
else x / y
let f (x:int) : (str,int) either =
handle (div 42 x) with
return (y:int) ! Right y
fail (y:str) ! Left y
Declare fail operation
Invoke fail
!6
7. Example
effect fail : str ! unit
let div (x:int) (y:int) =
if y = 0 then (#fail “div0”; -1)
else x / y
let f (x:int) : (str,int) either =
handle (div 42 x) with
return (y:int) ! Right y
fail (y:str) ! Left y
Declare fail operation
Invoke fail
Inject interpretation into effects
invoked in “div 42 x”
!7
8. Example
effect fail : str ! unit
let div (x:int) (y:int) =
if y = 0 then (#fail “div0”; -1)
else x / y
let f (x:int) : (str,int) either =
handle (div 42 x) with
return (y:int) ! Right y
fail (y:str) ! Left y
Declare fail operation
Invoke fail
Inject interpretation into effects
invoked in “div 42 x”
Interpretation of
fail operation
!8
9. Example
effect fail : str ! unit
let div (x:int) (y:int) =
if y = 0 then (#fail “div0”; -1)
else x / y
let f (x:int) : (str,int) either =
handle (div 42 x) with
return (y:int) ! Right y
fail (y:str) ! Left y
Declare fail operation
Invoke fail
Inject interpretation into effects
invoked in “div 42 x”
f 0 Left “div0”⟶
Interpretation of
fail operation
!8
10. Example
effect fail : str ! unit
let div (x:int) (y:int) =
if y = 0 then (#fail “div0”; -1)
else x / y
let f (x:int) : (str,int) either =
handle (div 42 x) with
return (y:int) ! Right y
fail (y:str) ! Left y
Declare fail operation
Invoke fail
f 0 Left “div0”⟶
Inject interpretation into effects
invoked in “div 42 x”
Evaluated with
the value of “div 42 x”
Interpretation of
fail operation
!9
11. Example
effect fail : str ! unit
let div (x:int) (y:int) =
if y = 0 then (#fail “div0”; -1)
else x / y
let f (x:int) : (str,int) either =
handle (div 42 x) with
return (y:int) ! Right y
fail (y:str) ! Left y
Declare fail operation
Invoke fail
f 7 Right 6⟶f 0 Left “div0”⟶
Inject interpretation into effects
invoked in “div 42 x”
Evaluated with
the value of “div 42 x”
Interpretation of
fail operation
!9
12. Resumption
Handlers support resumption of the computation
from the point of the effect invocation
• Reminiscent of delimited continuation
effect choose : int × int ! int
handle #choose(1,2) +
#choose(10,20) with
return (x:int) ! x
choose (x:int,y:int) ! resume x
!10
13. Resumption
Handlers support resumption of the computation
from the point of the effect invocation
• Reminiscent of delimited continuation
effect choose : int × int ! int
handle #choose(1,2) +
#choose(10,20) with
return (x:int) ! x
choose (x:int,y:int) ! resume x
!10
14. Resumption
Handlers support resumption of the computation
from the point of the effect invocation
• Reminiscent of delimited continuation
effect choose : int × int ! int
handle #choose(1,2) +
#choose(10,20) with
return (x:int) ! x
choose (x:int,y:int) ! resume x
!10
15. Resumption
Handlers support resumption of the computation
from the point of the effect invocation
• Reminiscent of delimited continuation
effect choose : int × int ! int
handle #choose(1,2) +
#choose(10,20) with
return (x:int) ! x
choose (x:int,y:int) ! resume x
Return x as
the result of #choose
!11
16. Resumption
Handlers support resumption of the computation
from the point of the effect invocation
• Reminiscent of delimited continuation
effect choose : int × int ! int
handle #choose(1,2) +
#choose(10,20) with
return (x:int) ! x
choose (x:int,y:int) ! resume x
Return x as
the result of #choose
!11
17. Resumption
Handlers support resumption of the computation
from the point of the effect invocation
• Reminiscent of delimited continuation
effect choose : int × int ! int
handle #choose(1,2) +
#choose(10,20) with
return (x:int) ! x
choose (x:int,y:int) ! resume x
x := 1
Return x as
the result of #choose
!11
18. Resumption
Handlers support resumption of the computation
from the point of the effect invocation
• Reminiscent of delimited continuation
effect choose : int × int ! int
handle 1 +
#choose(10,20) with
return (x:int) ! x
choose (x:int,y:int) ! resume x
x := 1
Return x as
the result of #choose
!12
19. Resumption
Handlers support resumption of the computation
from the point of the effect invocation
• Reminiscent of delimited continuation
effect choose : int × int ! int
handle 1 +
#choose(10,20) with
return (x:int) ! x
choose (x:int,y:int) ! resume x
Return x as
the result of #choose
!13
20. Resumption
Handlers support resumption of the computation
from the point of the effect invocation
• Reminiscent of delimited continuation
effect choose : int × int ! int
handle 1 +
#choose(10,20) with
return (x:int) ! x
choose (x:int,y:int) ! resume x
Return x as
the result of #choose
!13
21. Resumption
effect choose : int × int ! int
handle 1 +
10 with
return (x:int) ! x
choose (x:int,y:int) ! resume x
Handlers support resumption of the computation
from the point of the effect invocation
• Reminiscent of delimited continuation
Return x as
the result of #choose
!14
22. Parameterized effects
effect α choose : α × α ! α
handle if #choose(true,false)
then 1 else 2 with
return (x:int) ! #choose(10,20) + x
bool choose (x,y) ! resume (x && y)
!15
23. Parameterized effects
effect α choose : α × α ! α
handle if #choose(true,false)
then 1 else 2 with
return (x:int) ! #choose(10,20) + x
bool choose (x,y) ! resume (x && y)
!16
Signature is parameterized over types
24. Parameterized effects
effect α choose : α × α ! α
handle if #choose(true,false)
then 1 else 2 with
return (x:int) ! #choose(10,20) + x
bool choose (x,y) ! resume (x && y)
!17
Signature is parameterized over types
α := bool
25. Parameterized effects
effect α choose : α × α ! α
handle if #choose(true,false)
then 1 else 2 with
return (x:int) ! #choose(10,20) + x
bool choose (x,y) ! resume (x && y)
!18
Signature is parameterized over types
α := bool
Effect “bool choose” is handled
26. Parameterized effects
effect α choose : α × α ! α
handle if #choose(true,false)
then 1 else 2 with
return (x:int) ! #choose(10,20) + x
bool choose (x,y) ! resume (x && y)
!19
Signature is parameterized over types
α := bool
α := int
Effect “bool choose” is handled
27. Parameterized effects
effect α choose : α × α ! α
handle if #choose(true,false)
then 1 else 2 with
return (x:int) ! #choose(10,20) + x
bool choose (x,y) ! resume (x && y)
!19
Effect “int choose” will be
handled by an outer handler
Signature is parameterized over types
α := bool
α := int
Effect “bool choose” is handled
30. Motivation
Detection of “Handler-Not-Found” error
!21
effect fail : str ! unit
let div (x:int) (y:int) =
if y = 0 then (#fail “div0”; -1)
else x / y
div 10 0
There are no
handlers for #fail
31. Effect(-and-type) system
A means to detect invoked effects statically
• Types contain information about effects
!22
τ1 ! τ2Function type
32. Effect(-and-type) system
A means to detect invoked effects statically
• Types contain information about effects
!22
τ1 ! τ2Function type ε
Functions of this type may invoke effects ε
33. Row-based effect system
[Hillerström+ ’16; Leijen ’17; Lindley+ 17]
Effects ε are represented by a row
• It is originated from record typing
• Supported by Koka, Frank, Links, etc.
!23
34. Row-based effect system
[Hillerström+ ’16; Leijen ’17; Lindley+ 17]
Effects ε are represented by a row
• It is originated from record typing
• Supported by Koka, Frank, Links, etc.
!23
A sequence of effect names
〈 fail, int choose, … 〉
35. Row-based effect system
[Hillerström+ ’16; Leijen ’17; Lindley+ 17]
Effects ε are represented by a row
• It is originated from record typing
• Supported by Koka, Frank, Links, etc.
!23
A sequence of effect names
〈 fail, int choose, … 〉
τ1 !〈fail, int choose〉τ2
36. Row-based effect system
[Hillerström+ ’16; Leijen ’17; Lindley+ 17]
Effects ε are represented by a row
• It is originated from record typing
• Supported by Koka, Frank, Links, etc.
!23
A sequence of effect names
〈 fail, int choose, … 〉
Given to functions that may invoke
only “fail" and/or “int choose”
τ1 !〈fail, int choose〉τ2
37. Example
effect fail : str ! unit
let div (x:int) (y:int) =
if y = 0 then (#fail “div0”; -1)
else x / y
!24
let f (x:int) : (str,int) either =
handle (div 42 x) with
return (y:int) ! Right y
fail (y:str) ! Left y
38. Example
effect fail : str ! unit
let div (x:int) (y:int) =
if y = 0 then (#fail “div0”; -1)
else x / y
!24
div : int !〈〉int !〈fail〉int
let f (x:int) : (str,int) either =
handle (div 42 x) with
return (y:int) ! Right y
fail (y:str) ! Left y
39. Example
effect fail : str ! unit
let div (x:int) (y:int) =
if y = 0 then (#fail “div0”; -1)
else x / y
!24
div : int !〈〉int !〈fail〉int
let f (x:int) : (str,int) either =
handle (div 42 x) with
return (y:int) ! Right y
fail (y:str) ! Left y
f : int !〈〉(str, int) either
42. Example
!27
effect fail : str ! unit
type α opt = Some of α | None
let to-maybe (f : unit !〈fail〉α) : α opt =
handle f () with
return x ! Some x
fail _ ! None
to-maybe : ∀α. (unit !〈fail〉α) !〈〉α opt
43. Example
!27
effect fail : str ! unit
type α opt = Some of α | None
let to-maybe (f : unit !〈fail〉α) : α opt =
handle f () with
return x ! Some x
fail _ ! None
Problem: to-maybe cannot be applied to
functions invoking effects other than fail
Ex: to-maybe (fun () ! #choose(1,2))
to-maybe : ∀α. (unit !〈fail〉α) !〈〉α opt
44. Row polymorphism
Allowing functions to be parameterized over rows
!28
effect fail : str ! unit
let to-maybe (f : unit !〈fail, ρ〉α) =
handle f () with
return x ! Some x
fail _ ! None
45. Row polymorphism
Allowing functions to be parameterized over rows
!28
effect fail : str ! unit
let to-maybe (f : unit !〈fail, ρ〉α) =
handle f () with
return x ! Some x
fail _ ! None
Row variable
f will invoke fail and/or
effects substituted for ρ
46. Row polymorphism
Allowing functions to be parameterized over rows
!28
effect fail : str ! unit
let to-maybe (f : unit !〈fail, ρ〉α) =
handle f () with
return x ! Some x
fail _ ! None
∀α,ρ. (unit !〈fail,ρ〉α) !〈ρ〉α opt
to-maybe (fun () ! #choose(1,2))
by instantiating ρ with〈int choose〉
Row variable
f will invoke fail and/or
effects substituted for ρ
48. Duplication of effect names
• An effect can occur in multiple positions in a row
• Multiple parameterized effects with the same
name can occur in a row
!30
〈fail, int choose, fail〉
〈fail, int choose, bool choose〉
49. Benefits of duplication
• Functions can invoke effects given different
type parameters
• Simplifying the effect system, especially, with
row polymorphism
• Support for abstract effects
!31
50. Benefits of duplication
• Functions can invoke effects given different
type parameters
• Simplifying the effect system, especially, with
row polymorphism
• Support for abstract effects
!32
51. Benefit 1
Functions can invoke effects given different type
parameters
!33
let f () =
if #choose(true, false)
then #choose(1, 2)
else #choose(10, 20)
52. Benefit 1
Functions can invoke effects given different type
parameters
!33
let f () =
if #choose(true, false)
then #choose(1, 2)
else #choose(10, 20)
bool choose
53. Benefit 1
Functions can invoke effects given different type
parameters
!33
let f () =
if #choose(true, false)
then #choose(1, 2)
else #choose(10, 20)
bool choose
Int chooseint choose
54. Benefit 1
Functions can invoke effects given different type
parameters
!33
let f () =
if #choose(true, false)
then #choose(1, 2)
else #choose(10, 20)
bool choose
Int chooseint choose
f : unit !〈bool choose, int choose〉int
55. Handling duplicated effects
Effects are handled from the leftmost among
ones having the same name
!34
let f
(g : unit !〈int choose, bool choose〉unit) =
handle g () with
return x ! 0
int choose (x,y) ! 1
56. Handling duplicated effects
Effects are handled from the leftmost among
ones having the same name
!35
let f
(g : unit !〈int choose, bool choose〉unit) =
handle g () with
return x ! 0
bool choose (x,y) ! 1
57. Conclusion
• Algebraic effects & handlers are a means
to give user-defined effects
• Effect systems structure and analyze
effectful behavior of programs
• Row-based systems are expressive and
amenable
!36
58. Call for collaboration
Research interests
• New effect systems to capture and structure
effectful behavior
• Efficient implementation of effect handlers
• Practical applications of effects
(and continuations)
!37