Niki Vazou Mentor: Daan Leijen |
Similar examples:
Status: Success! (Prototype implementation on top of Koka)
javascript-like syntax
compiles to javascript
strongly typed
tracks effects (eg., exception, divergence, heap …)
“For all integers x,y
, x/y
will return an integer or throw an exception”
function (/) (x :int, y :int) : exn int
function effectful() : exn int {
val p = 42 / 2;
val q = 42 / 0;
p + q // p, q : int
}
exn
effect is propagated to user functions
p
and q
are pure integer values
function pure() : int {
catch(effectful, fun(err){0})
}
If effectful
throws an exception, return 0
function catch (action : () -> exn a, handler: exception -> a): a
Special built-in effects: exn
, div
, io
, …
Koka
already has polymorphic effect inference
Now support for user-defined effects
User defined effects are not just introducing a new type,
but are also a novel and powerful abstraction mechanism that
“let you take control of the semicolon”.
choice(x, y)
ambiguously returns x
or y
function choice( x : a, y : a) : amb a
function xor() : amb bool {
val p = choice(False, True);
val q = choice(False, True);
(p||q) && not(p&&q) // p, q : bool
}
amb
effect is propagated to user functions of choice
p
and q
are pure bool values
How do we evaluate xor
?
function run( action : () -> amb a ) : list<a>
run(action)
returns the list of all ambiguous results of action
> run(xor)
False
True
True
False
amb
is a monadic user-defined effect
is a monad if there exist functions and , such that
Example: list
is a monad!
function unit(x:a){[x]}
function bind(xs:list<a>, f:(a) -> list<b>): list<b>{
match(xs) {
Nil -> Nil
Cons(y,ys) -> f(y) + bind(ys, f)
}
}
The amb
effect is a list with the monadic operators
effect amb<a> = list<a> {
function unit( x:a ) : list<a> {
[x]
}
function bind( xs : list<a>, f : a -> list<b> ) : list<b> {
match(xs) {
Nil -> Nil
Cons(x,xx) -> f(x) + xx.bind(f)
}
}
}
koka
automatically generates
function from_amb(action : () -> amb a) : list<a>
function to_amb(xs:list<a>) : amb a
User Writes
function choice( x : a, y : a ) : amb a {
to_amb( [x,y] )
}
function run( action : () -> amb a ) : list<a> {
from_amb(action)
}
function xor() : amb bool{ //
val p = choice(False, True); // p is a list<bool> of all the amb results
val q = choice(False, True); //
(p||q) && not(p&&q) // p is treated as a bool
} //
Take control of the semicolon!
|
- |
|
bind : (list<a>, (a) -> list<b>) -> list<b>
unit : a -> list<a>
Which bind
and unit
should we use?
map
is polymorphic on effects
function map(xs : list<a>, f : (a) -> e b) : e list<b> {
match(xs) {
Nil -> Nil
Cons(y, ys) -> val z = f(y);
val zs = map(ys, f);
Cons(z, zs)
}
}
map
is polymorphic on effects
|
- |
|
Which bind
and unit
should we use?
bind
and unit
dict_amb
)
e
d:dict(e)
as extra argument
|
- |
|
function map : forall a b e. (xs:list<a>, f:(a) -> e b) -> e list<b>
function booltodoubles: (bool) -> amb double;
map(xs, booltodoubles)
koka intermediate effectfull code
map<bool, double, amb>(xs, booltodoubles)
translated koka intermediate monadic code
map<bool, double, amb>(dict_amb, xs, booltodoubles)
function map : forall<a,b,e> ( list<a>, (a) -> e b) -> e list<b>
function booltodouble: (bool) -> double;
map(xs, booltodouble)
koka intermediate effectfull code
map<bool, double, total>(xs, booltodouble)
translated koka intermediate monadic code
map<bool, double, total>(dict_id, xs, booltodouble)
Type-directed translation
Monadic User-Defined Effects
Thank you!