newtype Id a = Id a newtype Const a b = Const a data Pair f fs a = Pair (f a) (fs a) data Unary f fs a = Z (fs (fs a)) | S (Unary f (Pair f fs) a) type Square = Unary Id (Const ()) zero :: Square a zero = Z (Const ()) one :: Square Int one = S (Z (Pair (Id (Pair (Id 1) (Const ()))) (Const ()))) two :: Square Int two = S . S . Z $ Pair (Id $ Pair (Id 1) $ Pair (Id 2) $ Const ()) $ Pair (Id $ Pair (Id 3) $ Pair (Id 4) $ Const ()) $ Const ()