datatype exp = Int of int | Minus of exp * exp | Div of exp * exp;
datatype value = CVal of int
| FnVal of string * exp * (string * value) list
| Error of string;
fun eval (Int x) _ = CVal x
| eval (Div (e1, e2)) ctx = let val (CVal x) = eval e1 ctx
val (CVal y) = eval e2 ctx
in if y = 0
then Error "Division by zero error"
else CVal (x div y)
end
| eval (Minus (e1, e2)) ctx = let val (CVal x) = eval e1 ctx
val (CVal y) = eval e2 ctx
in if x <> Int orelse y <> Int
then Error "Minus error : not an integer"
else CVal (x - y)
end;
Int
is not a value, it's a constructor. You can't compare it to anything.
It's also a constructor of exp
values, not of integers.
If you look at your definition,
datatype value = CVal of int
...
it's clear that x
and y
must be integers, just like in the division case.
If you want to check types, you need to do that for division too, and you need to do that before you match with CVal x
and CVal y
.
This gets very messy if you try do it all in a single function, so I would write some evaluation-helper functions; something like this:
fun divide (CVal _) (CVal 0) = Error "Division by zero"
| divide (CVal x) (CVal y) = CVal (x div y)
| divide _ _ = Error "Division error: not an integer";
fun subtract (CVal x) (CVal y) = CVal (x - y)
| subtract _ _ = Error "Subtraction error: not an integer";
fun eval (Int x) _ = CVal x
| eval (Div (e1, e2)) ctx = let val x = eval e1 ctx
val y = eval e2 ctx
in
divide x y
end
| eval (Minus (e1, e2)) ctx = let val x = eval e1 ctx
val y = eval e2 ctx
in
subtract x y
end;