//! Implementation of the `st.State` effect let { Eff, inject_rest, ? } = import! std.effect let { map } = import! std.functor let { wrap } = import! std.applicative let { (<<) } = import! std.function let reference @ { Reference, ref, load } = import! std.st.reference.prim type STRef s a = Reference a #[infix(right, 9)] let (<-) = reference.(<-) /// The `State` effect enables the use of mutable state. By branding the state with `s` the mutable /// values are prevented from escaping the monad. type State s r a = | Call : forall b . (() -> b) -> State s r b .. r #[inline(never)] let extract_state x : forall s . [| st : State s | r |] a -> State s r a = convert_variant! x #[inline(never)] let send_state f : forall s . State s r a -> Eff [| st : State s | r |] a = Impure (convert_effect! st f) Pure let make_call = Call /// Creates a new mutable reference that contains `a`. let new_ref a : forall s . a -> Eff [| st : State s | r |] (STRef s a) = send_state (Call (\_ -> ref a)) /// Reads the values stored in the reference. let read_ref ref : forall s . STRef s a -> Eff [| st : State s | r |] a = send_state (Call (\_ -> load ref)) /// Writes a new value into the reference. let write_ref a ref : forall s . a -> STRef s a -> Eff [| st : State s | r |] () = send_state (Call (\_ -> ref <- a)) /// Eliminates the `State` effect let run_state eff : (forall s . Eff [| st : State s | r |] a) -> Eff [| | r |] a = let loop ve : forall s . Eff [| st : State s | r |] a -> Eff [| | r |] a = match ve with | Pure value -> wrap value | Impure e f -> match extract_state e with | Call g -> loop (f (g ())) | rest -> Impure (inject_rest rest) (loop << f) loop eff { State, STRef, send_state, new_ref, read_ref, write_ref, run_state, make_call, }