//! Implementation of the `Reader` effect
let { Eff, inject_rest, ? } = import! std.effect
let { map } = import! std.functor
let { wrap } = import! std.applicative
let { (<<) } = import! std.function
/// The `Reader` effects provides a shared, immutable environment for the effectful functions using it
type Reader s r a =
| Ask : Reader s r s
.. r
let extract_reader x : forall s . [| reader : Reader s | r |] a -> Reader s r a = convert_variant! x
let send_reader f : Reader s r a -> Eff [| reader : Reader s | r |] a =
Impure (convert_effect! reader f) Pure
/// Retrieve the value from the environment
let ask : forall s . Eff [| reader : Reader s | r |] s =
send_reader Ask
/// Retrieve the value from the environment while applying `f` to it
let asks f : forall s . (s -> a) -> Eff [| reader : Reader s | r |] a =
map f ask
/// Runs a computation in a modified environment.
let local f eff : forall s .
(s -> s) -> Eff [| reader : Reader s | r |] a -> Eff [| reader : Reader s | r |] a
=
do s = asks f
let s : s = s
// FIXME Remove after this does not affect inference
let loop ve : Eff [| reader : Reader s | r |] a -> Eff [| reader : Reader s | r |] a =
match ve with
| Pure value -> wrap value
| Impure e f ->
match extract_reader e with
| Ask ->
loop (f s)
| rest ->
Impure (inject_rest rest) (loop << f)
loop eff
/// Eliminates the `Reader` effect
let run_reader s eff : forall s . s -> Eff [| reader : Reader s | r |] a -> Eff [| | r |] a =
let loop reader ve : s -> Eff [| reader : Reader s | r |] a -> Eff [| | r |] a =
match ve with
| Pure value -> wrap value
| Impure e f ->
match extract_reader e with
| Ask ->
loop reader (f reader)
| rest ->
Impure (inject_rest rest) (loop reader << f)
loop s eff
{
Reader,
ask,
asks,
local,
run_reader,
}