//@ known-bug: #121575 // ignore-tidy-linelength #![feature(generic_const_exprs)] use std::array; trait PrimRec { fn eval(&self, x: [usize; N]) -> [usize; O]; } struct Zero; impl PrimRec for Zero { fn eval(&self, _: [usize; N]) -> [usize; 1] { [0] } } struct Const(usize); impl PrimRec for Const { fn eval(&self, _: [usize; N]) -> [usize; 1] { [self.0] } } struct S; impl PrimRec<1, 1> for S { fn eval(&self, x: [usize; 1]) -> [usize; 1] { [x[0] + 1] } } struct Proj; impl PrimRec for Proj { fn eval(&self, x: [usize; N]) -> [usize; 1] { [x[I]] } } struct Merge, B: PrimRec>( A, B, ); fn concat(a: [usize; M], b: [usize; N]) -> [usize; M + N] { array::from_fn(|i| if i < M { a[i] } else { b[i - M] }) } impl, B: PrimRec> PrimRec for Merge { fn eval(&self, x: [usize; N]) -> [usize; O1 + O2] { concat(self.0.eval(x), self.1.eval(x)) } } struct Compose, B: PrimRec>( A, B, ); impl, B: PrimRec> PrimRec for Compose { fn eval(&self, x: [usize; N]) -> [usize; O] { self.1.eval(self.0.eval(x)) } } struct Rec, F: PrimRec<{ O + (N + 1) }, O>>( Base, F, ); fn tail(x: [usize; N + 1]) -> [usize; N] { array::from_fn(|i| x[i + 1]) } fn cons(x: usize, xs: [usize; N]) -> [usize; N + 1] { array::from_fn(|i| if i == 0 { x } else { xs[i - 1] }) } impl, F: PrimRec<{ O + (N + 1) }, O>> PrimRec<{ N + 1 }, O> for Rec { fn eval(&self, x: [usize; N + 1]) -> [usize; O] { match (x[0], tail(x)) { (0, x) => self.0.eval(x), (y, x) => { let xy = cons(y - 1, x); let input = concat(self.eval(xy), xy); self.1.eval(input) } } } } fn main() { let one = Compose(Zero, S); dbg!(one.eval([])); let add: Rec<1, 1, Proj<0>, Compose<3, 1, 1, Proj<0>, S>> = Rec(Proj::<0>, Compose(Proj::<0>, S)); dbg!(add.eval([3, 2])); }