use std::marker::PhantomData; pub trait Rev { type Input; type Output; fn forward(&self, i: Self::Input) -> Self::Output; fn reverse(&self, o: Self::Output) -> Self::Input; } #[derive(Clone)] pub struct Addition { amount: A } impl Rev for Addition where A: std::ops::Add + std::ops::Sub + Copy { type Input = A; type Output = A; fn forward(&self, a: A) -> A { a + self.amount } fn reverse(&self, b: A) -> A { b - self.amount } } pub fn plus(amount: A) -> Addition { Addition { amount } } // more blocks #[derive(Clone)] pub struct Negate(PhantomData); impl> Rev for Negate { type Input = A; type Output = A; fn forward(&self, a: Self::Input) -> Self::Output { -a } fn reverse(&self, b: Self::Output) -> Self::Input { -b } } pub fn neg() -> Negate { Negate(PhantomData) } #[derive(Clone)] pub struct Multiplication { amount: A } impl Rev for Multiplication where A: std::ops::Mul + std::ops::Div + Copy, { type Input = A; type Output = A; fn forward(&self, a: A) -> A { a * self.amount } fn reverse(&self, b: A) -> A { b / self.amount } } pub fn times(amount: A) -> Multiplication { Multiplication { amount } } #[derive(Clone)] pub struct DiscreteMap(Vec<(A, B)>); impl Rev for DiscreteMap { type Input = A; type Output = B; fn forward(&self, a: A) -> B { for i in self.0.iter() { if i.0 == a { return i.1.clone() } } panic!() } fn reverse(&self, b: B) -> A { for i in self.0.iter() { if i.1 == b { return i.0.clone() } } panic!() } } pub fn discrete(vec: Vec<(A, B)>) -> DiscreteMap { DiscreteMap(vec) } // combinators #[derive(Clone)] pub struct Pipe(X, Y); impl Rev for Pipe where X: Rev, Y: Rev { type Input = X::Input; type Output = Y::Output; fn forward(&self, a: Self::Input) -> Self::Output { self.1.forward(self.0.forward(a)) } fn reverse(&self, c: Self::Output) -> Self::Input { self.0.reverse(self.1.reverse(c)) } } #[derive(Clone)] pub struct Inverse(X); impl Rev for Inverse { type Input = X::Output; type Output = X::Input; fn forward(&self, a: Self::Input) -> Self::Output { self.0.reverse(a) } fn reverse(&self, b: Self::Output) -> Self::Input { self.0.forward(b) } } pub trait RevExt: Rev + Sized { fn then>(self, other: N) -> Pipe { Pipe(self, other) } fn inverse(self) -> Inverse { Inverse(self) } } impl RevExt for T {} pub fn under(op: Op, val: Val) -> impl Rev where Op: Rev + Clone, Val: Rev { op.clone().then(val).then(op.inverse()) }