I’m trying to write a simple GADT-based evaluator for typed expressions, with the following expression variant:
type 'a expr =
| Int : int -> int expr
| Neg : int expr -> int expr
| Bool : bool -> bool expr
| Not : bool expr -> bool expr
I’d like to write a single eval : 'a expr -> 'a
function that handles any expression type:
let rec eval (type a) (expr : a expr) : a =
match expr with
| Int n -> n
| Neg n -> - eval n
| Bool b -> b
| Not b -> not (eval b)
;;
This doesn’t compile, however. I get the following error (line 25 refers to the Not
branch of the match
):
File "main.ml", line 25, characters 24-25:
Error: This expression has type a expr but an expression was expected of type
int expr
Type a is not compatible with type int
Asking Merlin for the type of eval
gives me int expr -> int
, rather than 'a expr -> 'a
, as I expected.
Is such an eval
function even possible to write, or am I simply doing something wrong with type annotations or locally abstract types or something?
P.S. the following works fine, but is less satisfying:
let rec eval_bool (expr : bool expr) : bool =
match expr with
| Bool b -> b
| Not b -> not (eval_bool b)
and eval_int (expr : int expr) : int =
match expr with
| Int n -> n
| Neg n -> - eval_int n
;;