// data IntExpr = Val Int | Add Expr Expr // data MulExpr = Mul IntExpr Intexpr // type Expr = Either IntExpr MulExpr // data Either a b = Inl a | Inr b #![allow(dead_code)] pub enum IntExpr { Val(i32), Add(Box, Box), } impl IntExpr { fn eval(expr: IntExpr) -> i32 { match expr { IntExpr::Val(i) => i, IntExpr::Add(x, y) => Self::eval(*x) + Self::eval(*y), } } } pub enum MulExpr { Mul(Box, Box), } pub struct Expr(Coproduct); pub enum Coproduct { L(A), R(B), } impl Expr { fn eval(expr: Expr) -> i32 { match expr.0 { Coproduct::L(ie) => IntExpr::eval(ie), Coproduct::R(me) => match me { MulExpr::Mul(x, y) => IntExpr::eval(*x) * IntExpr::eval(*y), }, } } } fn main() {} #[cfg(test)] mod tests { use super::*; #[test] fn simple_eval_expression() { // I can't add MulExpr inside IntExpr!! let expr = Expr(Coproduct::L(IntExpr::Add( Box::new(IntExpr::Val(2)), Box::new(IntExpr::Val(3)), ))); assert_eq!(5, Expr::eval(expr)) } }