-
-
Save faiface/a4af36c5733cac8fb32812c901751aad to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pub trait Proc: 'static { | |
type Then<P: Proc>: Proc; | |
type Dual: Proc; | |
fn extend(this: Self) -> Self::Then<Noop>; | |
fn map<P: Proc, Q: Proc>(this: Self::Then<P>, f: impl 'static + FnOnce(P) -> Q) -> Self::Then<Q>; | |
fn apply<P: Proc>(src: Self::Dual, dst: Self::Then<P>) -> P; | |
fn then_assc<P: Proc, Q: Proc>(this: Self::Then<P::Then<Q>>) -> <Self::Then<P> as Proc>::Then<Q>; | |
fn dual_dist<P: Proc>(this: <Self::Dual as Proc>::Then<P::Dual>) -> <Self::Then<P> as Proc>::Dual; | |
} | |
pub struct Noop; | |
pub struct Put<T, P: Proc> { inner: (T, P) } | |
pub struct Get<T, P: Proc> { inner: Box<dyn FnOnce(T) -> P> } | |
pub struct Choice<P: Proc, Q: Proc> { inner: Either<P, Q> } | |
pub struct Branch<P: Proc, Q: Proc> { inner: Box<dyn Select<P, Q>> } | |
pub struct Recur<P: Proc, Q: Proc> { inner: Either<Q, Box<P::Then<Recur<P, Q>>>> } | |
pub struct Corec<P: Proc, Q: Proc> { inner: Box<dyn Select<Q, P::Then<Corec<P, Q>>>> } | |
impl Proc for Noop { | |
type Then<P: Proc> = P; | |
type Dual = Noop; | |
fn extend(this: Self) -> Self::Then<Noop> { | |
this | |
} | |
fn map<P: Proc, Q: Proc>(this: Self::Then<P>, f: impl FnOnce(P) -> Q) -> Self::Then<Q> { | |
f(this) | |
} | |
fn apply<P: Proc>(_: Self::Dual, dst: Self::Then<P>) -> P { | |
dst | |
} | |
fn then_assc<P: Proc, Q: Proc>(this: Self::Then<P::Then<Q>>) -> <Self::Then<P> as Proc>::Then<Q> { | |
this | |
} | |
fn dual_dist<P: Proc>(this: <Self::Dual as Proc>::Then<P::Dual>) -> <Self::Then<P> as Proc>::Dual { | |
this | |
} | |
} | |
impl<T: 'static, P: Proc> Proc for Put<T, P> { | |
type Then<Q: Proc> = Put<T, P::Then<Q>>; | |
type Dual = Get<T, P::Dual>; | |
fn extend(this: Self) -> Self::Then<Noop> { | |
Put { inner: (this.inner.0, P::extend(this.inner.1)) } | |
} | |
fn map<Q: Proc, R: Proc>(this: Self::Then<Q>, f: impl 'static + FnOnce(Q) -> R) -> Self::Then<R> { | |
Put { inner: (this.inner.0, P::map(this.inner.1, f)) } | |
} | |
fn apply<Q: Proc>(src: Self::Dual, dst: Self::Then<Q>) -> Q { | |
P::apply((src.inner)(dst.inner.0), dst.inner.1) | |
} | |
fn then_assc<Q: Proc, R: Proc>(this: Self::Then<Q::Then<R>>) -> <Self::Then<Q> as Proc>::Then<R> { | |
Put { inner: (this.inner.0, P::then_assc(this.inner.1)) } | |
} | |
fn dual_dist<Q: Proc>(this: <Self::Dual as Proc>::Then<Q::Dual>) -> <Self::Then<Q> as Proc>::Dual { | |
Get { inner: Box::new(move |value| P::dual_dist((this.inner)(value))) } | |
} | |
} | |
impl<T: 'static, P: Proc> Proc for Get<T, P> { | |
type Then<Q: Proc> = Get<T, P::Then<Q>>; | |
type Dual = Put<T, P::Dual>; | |
fn extend(this: Self) -> Self::Then<Noop> { | |
Get { inner: Box::new(move |value| P::extend((this.inner)(value))) } | |
} | |
fn map<Q: Proc, R: Proc>(this: Self::Then<Q>, f: impl 'static + FnOnce(Q) -> R) -> Self::Then<R> { | |
Get { inner: Box::new(move |value| P::map((this.inner)(value), f)) } | |
} | |
fn apply<Q: Proc>(src: Self::Dual, dst: Self::Then<Q>) -> Q { | |
P::apply(src.inner.1, (dst.inner)(src.inner.0)) | |
} | |
fn then_assc<Q: Proc, R: Proc>(this: Self::Then<Q::Then<R>>) -> <Self::Then<Q> as Proc>::Then<R> { | |
Get { inner: Box::new(move |value| P::then_assc((this.inner)(value))) } | |
} | |
fn dual_dist<Q: Proc>(this: <Self::Dual as Proc>::Then<Q::Dual>) -> <Self::Then<Q> as Proc>::Dual { | |
Put { inner: (this.inner.0, P::dual_dist(this.inner.1)) } | |
} | |
} | |
impl<P: Proc, Q: Proc> Proc for Choice<P, Q> { | |
type Then<R: Proc> = Choice<P::Then<R>, Q::Then<R>>; | |
type Dual = Branch<P::Dual, Q::Dual>; | |
fn extend(this: Self) -> Self::Then<Noop> { | |
match this.inner { | |
Either::Left(left) => Choice { inner: Either::Left(P::extend(left)) }, | |
Either::Right(right) => Choice { inner: Either::Right(Q::extend(right)) } | |
} | |
} | |
fn map<R: Proc, S: Proc>(this: Self::Then<R>, f: impl 'static + FnOnce(R) -> S) -> Self::Then<S> { | |
match this.inner { | |
Either::Left(left) => Choice { inner: Either::Left(P::map(left, f)) }, | |
Either::Right(right) => Choice { inner: Either::Right(Q::map(right, f)) }, | |
} | |
} | |
fn apply<R: Proc>(src: Self::Dual, dst: Self::Then<R>) -> R { | |
match dst.inner { | |
Either::Left(left) => P::apply(src.inner.left(), left), | |
Either::Right(right) => Q::apply(src.inner.right(), right), | |
} | |
} | |
fn then_assc<R: Proc, S: Proc>(this: Self::Then<R::Then<S>>) -> <Self::Then<R> as Proc>::Then<S> { | |
match this.inner { | |
Either::Left(left) => Choice { inner: Either::Left(P::then_assc(left)) }, | |
Either::Right(right) => Choice { inner: Either::Right(Q::then_assc(right)) }, | |
} | |
} | |
fn dual_dist<R: Proc>(this: <Self::Dual as Proc>::Then<R::Dual>) -> <Self::Then<R> as Proc>::Dual { | |
Branch { inner: Box::new(MakeSelect { | |
state: this, | |
left: |this| P::dual_dist(this.inner.left()), | |
right: |this| Q::dual_dist(this.inner.right()), | |
}) } | |
} | |
} | |
impl<P: Proc, Q: Proc> Proc for Branch<P, Q> { | |
type Then<R: Proc> = Branch<P::Then<R>, Q::Then<R>>; | |
type Dual = Choice<P::Dual, Q::Dual>; | |
fn extend(this: Self) -> Self::Then<Noop> { | |
Branch { inner: Box::new(MakeSelect { | |
state: this, | |
left: |this| P::extend(this.inner.left()), | |
right: |this| Q::extend(this.inner.right()), | |
}) } | |
} | |
fn map<R: Proc, S: Proc>(this: Self::Then<R>, f: impl 'static + FnOnce(R) -> S) -> Self::Then<S> { | |
Branch { inner: Box::new(MakeSelect { | |
state: (this, f), | |
left: |(this, f)| P::map(this.inner.left(), f), | |
right: |(this, f)| Q::map(this.inner.right(), f), | |
}) } | |
} | |
fn apply<R: Proc>(src: Self::Dual, dst: Self::Then<R>) -> R { | |
match src.inner { | |
Either::Left(left) => P::apply(left, dst.inner.left()), | |
Either::Right(right) => Q::apply(right, dst.inner.right()), | |
} | |
} | |
fn then_assc<R: Proc, S: Proc>(this: Self::Then<R::Then<S>>) -> <Self::Then<R> as Proc>::Then<S> { | |
Branch { inner: Box::new(MakeSelect { | |
state: this, | |
left: |this| P::then_assc(this.inner.left()), | |
right: |this| Q::then_assc(this.inner.right()), | |
}) } | |
} | |
fn dual_dist<R: Proc>(this: <Self::Dual as Proc>::Then<R::Dual>) -> <Self::Then<R> as Proc>::Dual { | |
match this.inner { | |
Either::Left(left) => Choice { inner: Either::Left(P::dual_dist(left)) }, | |
Either::Right(right) => Choice { inner: Either::Right(Q::dual_dist(right)) }, | |
} | |
} | |
} | |
impl<P: Proc, Q: Proc> Proc for Recur<P, Q> { | |
type Then<R: Proc> = Recur<P, Q::Then<R>>; | |
type Dual = Corec<P::Dual, Q::Dual>; | |
fn extend(this: Self) -> Self::Then<Noop> { | |
match this.inner { | |
Either::Left(left) => Recur { inner: Either::Left(Q::extend(left)) }, | |
Either::Right(box right) => Recur { | |
inner: Either::Right(Box::new(P::map(right, move |recur| Self::extend(recur)))), | |
} | |
} | |
} | |
fn map<R: Proc, S: Proc>(this: Self::Then<R>, f: impl 'static + FnOnce(R) -> S) -> Self::Then<S> { | |
match this.inner { | |
Either::Left(left) => Recur { inner: Either::Left(Q::map(left, f)) }, | |
Either::Right(box right) => Recur { | |
inner: Either::Right(Box::new(P::map(right, move |recur| Self::map(recur, f)))), | |
}, | |
} | |
} | |
fn apply<R: Proc>(src: Self::Dual, dst: Self::Then<R>) -> R { | |
match dst.inner { | |
Either::Left(left) => Q::apply(src.inner.left(), left), | |
Either::Right(box right) => <P::Then<Recur<P, Q>>>::apply(P::dual_dist(src.inner.right()), P::then_assc(right)), | |
} | |
} | |
fn then_assc<R: Proc, S: Proc>(this: Self::Then<R::Then<S>>) -> <Self::Then<R> as Proc>::Then<S> { | |
match this.inner { | |
Either::Left(left) => Recur { inner: Either::Left(Q::then_assc(left)) }, | |
Either::Right(box right) => Recur { | |
inner: Either::Right(Box::new(P::map(right, move |recur| Self::then_assc(recur)))), | |
}, | |
} | |
} | |
fn dual_dist<R: Proc>(this: <Self::Dual as Proc>::Then<R::Dual>) -> <Self::Then<R> as Proc>::Dual { | |
Corec { inner: Box::new(MakeSelect { | |
state: this, | |
left: |this| Q::dual_dist(this.inner.left()), | |
right: |this| <P::Dual>::map(this.inner.right(), move |recur| Self::dual_dist(recur)), | |
}) } | |
} | |
} | |
impl<P: Proc, Q: Proc> Proc for Corec<P, Q> { | |
type Then<R: Proc> = Corec<P, Q::Then<R>>; | |
type Dual = Recur<P::Dual, Q::Dual>; | |
fn extend(this: Self) -> Self::Then<Noop> { | |
Corec { inner: Box::new(MakeSelect { | |
state: this, | |
left: |this| Q::extend(this.inner.left()), | |
right: |this| P::map(this.inner.right(), move |corec| Self::extend(corec)), | |
}) } | |
} | |
fn map<R: Proc, S: Proc>(this: Self::Then<R>, f: impl 'static + FnOnce(R) -> S) -> Self::Then<S> { | |
Corec { inner: Box::new(MakeSelect { | |
state: (this, f), | |
left: |(this, f)| Q::map(this.inner.left(), f), | |
right: |(this, f)| P::map(this.inner.right(), move |corec| Self::map(corec, f)), | |
}) } | |
} | |
fn apply<R: Proc>(src: Self::Dual, dst: Self::Then<R>) -> R { | |
match src.inner { | |
Either::Left(left) => Q::apply(left, dst.inner.left()), | |
Either::Right(box right) => <P::Then<Corec<P, Q>>>::apply(P::dual_dist(right), P::then_assc(dst.inner.right())), | |
} | |
} | |
fn then_assc<R: Proc, S: Proc>(this: Self::Then<R::Then<S>>) -> <Self::Then<R> as Proc>::Then<S> { | |
Corec { inner: Box::new(MakeSelect { | |
state: this, | |
left: |this| Q::then_assc(this.inner.left()), | |
right: |this| P::map(this.inner.right(), move |corec| Self::then_assc(corec)), | |
}) } | |
} | |
fn dual_dist<R: Proc>(this: <Self::Dual as Proc>::Then<R::Dual>) -> <Self::Then<R> as Proc>::Dual { | |
match this.inner { | |
Either::Left(left) => Recur { inner: Either::Left(Q::dual_dist(left)) }, | |
Either::Right(box right) => Recur { | |
inner: Either::Right(Box::new(<P::Dual>::map(right, move |recur| Self::dual_dist(recur)))), | |
}, | |
} | |
} | |
} | |
enum Either<A, B> { | |
Left(A), | |
Right(B), | |
} | |
trait Select<A, B> { | |
fn left(self: Box<Self>) -> A; | |
fn right(self: Box<Self>) -> B; | |
} | |
struct MakeSelect<S, A, B> { | |
state: S, | |
left: fn(S) -> A, | |
right: fn(S) -> B, | |
} | |
impl<S, A, B> Select<A, B> for MakeSelect<S, A, B> { | |
fn left(self: Box<Self>) -> A { | |
(self.left)(self.state) | |
} | |
fn right(self: Box<Self>) -> B { | |
(self.right)(self.state) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment