fx_rs/kernel/
fx.rs

1use super::Ability;
2
3#[derive(Clone)]
4pub struct Fx<'f, S: Clone, V: Clone>(Eff<'f, S, V>);
5
6#[derive(Clone)]
7enum Eff<'f, S: Clone, V: Clone> {
8    Immediate(S, V),
9    Pending(Ability<'f, S, S, V>),
10}
11
12impl<V: Clone> Fx<'_, (), V> {
13    pub fn eval(self) -> V {
14        let mut e = self;
15        loop {
16            match e.0 {
17                Eff::Immediate((), v) => return v,
18                Eff::Pending(f) => e = f.apply(()),
19            }
20        }
21    }
22}
23
24impl<'f, S: Clone, V: Clone> Fx<'f, S, V> {
25    pub fn immediate(s: S, value: V) -> Self {
26        Fx(Eff::Immediate(s, value))
27    }
28
29    pub fn pending<F>(f: F) -> Self
30    where
31        F: FnOnce(S) -> Self + Clone + 'f,
32    {
33        Fx(Eff::Pending(Ability::new(f)))
34    }
35
36    pub fn adapt<T, U, C, F>(self, cmap: C, fmap: F) -> Fx<'f, T, U>
37    where
38        T: Clone,
39        S: Clone,
40        U: Clone,
41        C: FnOnce(T) -> S + Clone + 'f,
42        F: FnOnce(T, S, V) -> Fx<'f, T, U> + Clone + 'f,
43    {
44        Fx::pending(|t: T| match self.0 {
45            Eff::Immediate(s, v) => fmap(t, s, v),
46            Eff::Pending(f) => f.apply(cmap.clone()(t)).adapt(cmap, fmap),
47        })
48    }
49}