Cameron Moy
This package has not been officially released. Backwards compatibility is not guaranteed.
This package provides support for effect handlers, both as a library, and as a language. Here is an implementation of first-class mutable references:
[(box-getb)[(box-setbv)
We define a struct named box that will hold a default value, i.e., the value to return if the box has no mapping in the store. Two operations, declared with effect , will be interpreted by an effect handler. The store-service function takes in a store and returns a first-class handler that interprets box effects in that store.
For box-get, we look up the given box in the store. If the box has a mapping in the store, then the mapped value is returned. Otherwise, the default value is returned. To return a value, the continue function is invoked. This function is bound to a delimited continuation from the point where the effect was requested up to and including the handler itself. In the effect handler literature, this is known as a deep handler.
For box-set, we construct a new store that maps the box to its new value. The continuation is then executed in a context where operations are handled by a new handler, with the updated store. This time, we use continue* to invoke the delimited continuation up to but not including the handler itself. In the effect handler literature, this is known as a shallow handler. Using continue* allows us to reinterpret subsequent effects using a different handler.
Here is how this box implementation is used:
1
A language, effect/racket, provides effect handlers and ensures that all built-in operations cooperate with effect handlers too.
This program reinterprets read to take input from a list of strings, rather than standard in.
The function fixed-input-service takes in a list of values and feeds that list to read , one by one. Here is how that might be used:
(add-from-inputs))3
Note that an effect/racket module can only require from other effect/racket modules. There is no interoperability between effect/racket and other languages. Higher-order values imported across the language boundary will be sealed, i.e, unusable.
syntax
( effect id(param...))
id as a procedure that performs the given effect. This procedure accepts an optional keyword argument #:fail that, given a failure-result/c , calls that thunk (or yields that value) when no handler exists for the effect in the current context.
id as a match pattern that matches effect values created by id.
id? is a predicate that succeeds on effect values created by id.
procedure
( effect-value? v)→boolean?
v:any/c
syntax
( return val...)
[(fail)'()]
So that the append works uniformly, return is used to inject values from pure expressions into a list. It can be used as such:
'((#t . #f) (#f . #t) (#f . #f))
This effect can also be invoked directly, for early return behavior.
10
syntax
( handler [patbody...+]...)
Both continue and continue* are bound in the bodies of each handler arm to a deep and shallow delimited continuation, respectively.
syntax
( contract-handler [patbody...+]...)
1
f: contract violation
expected: limited?
given: 1
in: the 1st argument of
(-> limited? any)
contract from: (function f)
blaming: top-level
(assuming the contract is correct)
at: eval:17:0
procedure
( handler-append v...)→handler?
v:handler?
(go10))19
syntax
( with (handler...)body...+)
syntax
( splicing-with (handler...)body...+)
'(2 3 4)
my-map: contract violation;
none/c allows no values
given: (write 1)
in: the performed effect
the 1st argument of
(->
(->e none/c ...rivate/contract.rkt:40:3)
(listof any/c)
(listof any/c))
contract from: (function my-map)
blaming: top-level
(assuming the contract is correct)
at: eval:27:0
procedure
( dependent->e effmake-ret)→contract?
eff:contract?
42
f: contract violation
expected: (=/c 42)
given: 0
in: the effect response
(->e id? composed)
contract from: (function f)
blaming: top-level
(assuming the contract is correct)
at: eval:31:0
2
id: contract violation
#:pre condition
in: (->* (any/c) #:pre ... any)
contract from: (function id)
blaming: top-level
(assuming the contract is correct)
at: eval:37:0