Polymorphic evaluator in Haskell

Viewed 72

How can I edit the following code so that I don't have so many evaluators (which right now reflect various result types)? I want a single evaluator so that I don't know in advance the type of the result. I want one evaluator for the whole language. Do I need to add a value type for Exp to do this? How would this look like? What kind of value type and how would I edit the current eval functions in order to reflect this new polymorphic type?

{-# LANGUAGE TypeSynonymInstances, FlexibleInstances #-}

data Exp = V Var
    | B Bool
    | MyInt Int
    | And Exp Exp
    | Or Exp Exp
    | Not Exp
    | Mult Exp Exp
    | UnaryNeg Exp
    | LEQ Exp Exp
    | LESST Exp Exp
    | Add Exp Exp 
    | POLYEQ Exp Exp
data Var = VZ |VS Var

eval:: Exp -> Int
eval (MyInt e1)     = e1
eval (UnaryNeg e1)     = - (eval e1)
eval (Mult e1 e2) = eval e1 * eval e2
eval (Add e1 e2) = eval e1 + eval e2

eval0:: Exp -> Bool
eval0 (B e1) = e1
eval0 (Not e1) = not (eval0 e1)
eval0 (And e1 e2) = (eval0 e1) && (eval0 e2)
eval0 (Or e1 e2) = (eval0 e1) || (eval0 e2)
eval0 (LEQ e1 e2) = eval e1 <= eval e2
eval0 (LESST e1 e2) = eval e1 < eval e2

eval1:: Exp -> Bool
eval1 (POLYEQ e1 e2) = eval0 e1 == eval0 e2
1 Answers

The standard solution is to have the expression type annotated with what type of result it represents. This will then be a Generalised Algebraic Data Type:

{-# LANGUAGE GADTs #-}

data Exp a where
   V :: Var -> Exp a
   B :: Bool -> Exp Bool
   MyInt :: Int -> Exp Int
   And :: Exp Bool -> Exp Bool -> Exp Bool
   POLYEQ :: Exp a -> Exp a -> Exp Bool
   ...

Then you need only one evaluation function, whose result will be whatever the type represented by the expression:

eval :: Exp a -> a
eval (MyInt e1) = e1
eval (B  e1) = e1
...
Related