Very cool idea! More of an arcade game though than a roguelike, but very enjoyable. One nit i have: it seems like the seed is fixed? where units spawn every turn.
pair a b = '(pair a b)
where ' is shorthand for quoting, like in lisp. If you want to explicitly define datatypes on demand, you can just manually quote and not use the pair function constructor. One thing I thought about to was smart constructors, like say if you want to define the mod 3 group: zero = 'zero
s (s (s x))) = x
s x = '(s x)
if values are always constructed with either "s" or "zero", the smart constructor of s enforces you can't create any terms with an s-chain of 3 or higher, IF the function arguments are eagerly evaluated.