We can define a data type of expressions in our language, with addition, multiplication, etc.
data Expr = Addition Expr Expr | Multiplication Expr Expr | ...
Then we need the type of an interpreter which consumes program inputs and produces an output. I'll leave this abstract for now. data Interpreter = ...
By map, we just mean that we can write a Haskell function with this type interpret :: Expr -> Interpreter
interpret (Addition a b) = (+) <$> interpret a <*> interpret b
interpret (Multiplication a b) = (*) <$> interpret a <*> interpret b
If you're curious, here's some real symbolic evaluation code I wrote doing the same https://github.com/kadena-io/pact/blob/234ba3dd01f0df8b4e462...