One can define a Num instance in Haskell for ASTs of expressions, viz.

data BinOp = Plus | Minus | Mul | Div

data Exp = Int Integer | BinOp BinOp Exp Exp

instance Num Exp where (+) = BinOp Plus (*) = BinOp Times (-) = BinOp Minus

fromInteger = Int

I use this in my Apple compiler.

sum over a list will construct a syntax tree:

λ:> sum [1,2,3,4,5::Exp] (+ (+ (+ (+ (+ (int 0) (int 1)) (int 2)) (int 3)) (int 4)) (int 5))

This is a nice way to see the difference between foldl and foldr:

λ:> (foldl1 (+) [1,2,3,4,5::Exp]) (+ (+ (+ (+ (int 1) (int 2)) (int 3)) (int 4)) (int 5))

λ:> (foldr1 (+) [1,2,3,4,5::Exp]) (+ (int 1) (+ (int 2) (+ (int 3) (+ (int 4) (int 5)))))

Using the compiler backend, sum [1,2,3,4,5] can be used to define a series of assembly instructions that evaluates the sum of [1,2,3,4,5]:

λ:> pAsm $ evalAarch64 (sum [1,2,3,4,5]) mov T5, #0x0 add T4, T5, #0x1 add T3, T4, #0x2 add T2, T3, #0x3 add T1, T2, #0x4 add X0, T1, #0x5

Cute!