Skip to content

Instantly share code, notes, and snippets.

@faiface
Last active December 18, 2023 18:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save faiface/a4af36c5733cac8fb32812c901751aad to your computer and use it in GitHub Desktop.
Save faiface/a4af36c5733cac8fb32812c901751aad to your computer and use it in GitHub Desktop.
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