6. Programming with ADTs

1. A dictionary is a collection of key-value pairs, which we can represent in Haskell as a list of pairs (String,Integer) where String is the key type and Integer is the value type:

type Dict = [(String,Integer)]

Implement the function valueOf which takes a key and a dictionary, and returns the associated value. It is guaranteed that the value exists.

valueOf :: String -> Dict -> Integer

2. Implement the function ins which takes a key s, a value i, a dictionary d and updates the value of s in the dictionary, if the value exists, or adds the key-value pair, otherwise. For instance ins “x” 1 [(“x”,0)] = [(“x”,1)] and ins “x” 1 [(“y”,0)] = [(“x”,1),(“y”,0)].

ins :: String -> Integer -> Dict -> Dict

3. Consider the type PExpr of program expressions defined in the lecture. Implement a function for showing PExpr values:

data PExpr = Val Integer |
             Var String  |
             PExpr :+: PExpr 
 
show_pexpr :: PExpr -> String             

4. Implement a function which takes a dictionary of program variables, a program expression PExpr, and evaluates it. For instance: eval_pexpr [(“x”,2),(“y”,1)] ( (Var “x”) :+: (Var “y”) ) returns 3.

eval_pexpr :: Dict -> PExpr -> Integer

5. Consider the type BExpr of boolean expressions defined in the lecture. Implement a function for displaying values of BExpr:

data BExpr = PExpr :==: PExpr | 
            PExpr :<: PExpr |
            Not BExpr |
            BExpr :&&: BExpr 
 
show_bexpr :: BExpr -> String

Add the following code to your program:

instance Show PExpr where
    show = show_pexpr
 
instance Show BExpr where
    show = show_bexpr    

6. Write a function which, given a dictionary, evaluates boolean conditions BExpr:

eval_bexpr :: Dict -> BExpr -> Bool

Add the following code (from the lecture) to your program:

data Prog = PlusPlus Var |        -- x++;
            Var :=: PExpr |     -- x = <expr>;
            DeclareInt Var |      -- int x;
            Begin Prog Prog |     -- <p> <p'>
            While BExpr Prog |     -- while (<expr>) { <p> }
            If BExpr Prog Prog      -- if (<expr>) { <p> } else { <p'> }   
 
show_p :: Prog -> String
show_p (PlusPlus v) = v++"++;\n"
show_p (x :=: e) = x++"="++(show_pexpr e)++";\n"
show_p (DeclareInt x) = "int "++x++";\n"
show_p (Begin p p') = (show_p p)++(show_p p')
show_p (While e p) = "while ("++(show_bexpr e)++") {\n"++(show_p p)++"}\n"
show_p (If e p p') = "if ("++(show_bexpr e)++") {\n"++(show_p p)++"}\n else {\n"++(show_p p')++"}\n"
 
instance Show Prog where
  show = show_p

7. Define the program:

int x;
x++;
while (x < 100){
   x = x + 1
}

8. Define a function eval which takes a dictionary and a program, and evaluates the program under the given dictionary. The function will return an updated dictionary. For instance:

eval [("x",0)] (PlusPlus "x") = [("x",1)]
eval [("x",1)] ("x" :=: ((Var "x") :+: (Val 1))) = [("x",2)]
eval [] (DeclareInt "x") = [("x",0)]
 
eval :: Dict -> Prog -> Dict

Add the following error-handling type to your program:

data Result a = Error String |  -- a value of type (Result a) is an error, or
                Value a         -- an actual value, wrapped by the data constructor Value

9. Implement the function check which takes a list of defined variables, a program p, and returns an updated list of variable definitions, if p does not contain undeclared variables, and an error message, otherwise.

check :: [Var] -> Prog -> Result [Var]

For instance:

check [] (DeclareInt "x") = Value ["x"]
check [] (PlusPlus "x") = Error "x is undefined"
check ["x"] (PlusPlus "x") = ["x"]