I’m experimenting with intercepting effects as in order to attach information to them, for example in order to prioritise certain fibres.
This as an idea seemingly does work, although there is many slightly weird type errors.
Throughout this I’m using the State
example.
After much trial and error here is a working example.
effect Get : string
effect Priority : 'a eff * string -> 'a
let run f ~init =
let comp =
match f () with
| x -> (fun s -> x)
| effect (Priority (Get, p)) k -> (fun (s : string) -> print_endline p; continue k s s)
in comp init
let priority f ~p =
match f () with
| x -> x
| effect Get k -> let r = perform (Priority (Get, p)) in continue k r;;
let () =
run ~init:"1" @@
@@ fun () -> priority ~p:"p"
@@ print_endline (perform Get)
Q1. You need to constrain the type of s
in run?
Unfortunately I don’t quite understand how some of the typing constraints passes around.
For example one persistent problem was that if s
is not constrained to be a string
its usage in the continue k s s
fails to type check:
Error: This expression has type 'a but an expression was expected of type
effect
This instance of effect is ambiguous:
it would escape the scope of its equation
Why is it expecting the type to be an effect
?
Q2. Polymorphic continuations cannot be passed via effects?
Additionally one change which would be nice to have would be to pass the continuation up through the priority effect, such that on the return the priority function would not need to be involved, ie:
effect Priority : 'a eff * ('a, 'b) continuation * string -> unit
let run f ~init =
let comp =
match f () with
| x -> (fun s -> x)
| effect (Priority (Get, k, _)) _ -> fun (s : string) -> continue k s s
in comp init
All variants I’ve tried to write using this unfortunately unify the 'b
with effect
, but I am not sure why this is occurring, if I manually type 'b : int
, run
type checks, but then it is not polymorphic.
Q3. Multiple effects leading to the same outcome?
Finally one nice simplification in these situations may be to have a match statement as follows:
let run f ~init =
let comp =
match f () with
| x -> (fun s -> s)
| effect (Priority (Get, k, _)) _
| effect Get k -> fun (s : string) -> continue k s s
However this fails with the error:
Effect patterns must be at the top level of a match case
Are these style of patterns just not possible using effects? I am fairly sure that it was possible to do similar patterns for exceptions, though I am probably mistaken.
Conclusion
I’m expecting that the answer to the first two of these is that I need to better constrain the type of Priority
, which I would love to hear how to do this .
If there is some underlying issue with this approach that would also be great to hear!
Overall though the new effects system is very very cool, super versatile and expressive!