data Lit i = Lit i; data Succ t = Succ t; data IsZero t = IsZero t; data If tc tt te = If tc tt te; class Term a where { type Result a; } instance Term Bool where { type Result Bool = Bool; } instance Term (Lit Int) where { type Result (Lit Int) = Int; } instance Term a, Result a = Int => Term (Succ a) where { type Result (Succ a) = Int; } instance Term a, Result a = Int => Term (IsZero a) where { type Result (IsZero a) = Bool; } instance Term a, Term b, Term c, Result a = Result b, Result c = Bool => Term (If c a b) where { type Result (If c a b) = Result a; } class Term a => Eval a where { eval :: a -> Result a; } instance Eval Bool where { eval b = b; } instance Eval (Lit Int) where { eval x = case x of Lit i -> i;; } instance Eval a, Result a = Int => Eval (Succ a) where { eval x = case x of Succ i -> eval i + 1;; } instance Eval a, Result a = Int => Eval (IsZero a) where { eval x = case x of IsZero i -> eval i == 0;; } instance Eval a, Eval b, Eval c, Result a = Result b, Result c = Bool => Eval (If c a b) where { eval x = case x of If c t1 t2 -> if eval c then eval t1 else eval t2;; } foo n = eval (If (IsZero (Succ n)) (Lit 42) n); main = foo (Lit (-1));