简体   繁体   中英

How do I interpret this GADT error in OCaml?

Sorry about the "what am I missing here" style of question here, but I'm just missing something here.

I was trying to understand how GADTs work in OCaml, I define the following (in utop ):

 type value =
| Bool : bool -> value
| Int : int -> value
;;

type _ value =
| Bool : bool -> bool value
| Int : int -> int value
;;

type _ expr =
| Value : 'a value -> 'a expr
| If : bool expr * 'a expr * 'a expr -> 'a expr
| Lt : 'a expr * 'a expr -> bool expr
| Eq : 'a expr * 'a expr -> bool expr
| Gt : 'a expr * 'a expr -> bool expr
;;

I defined an eval function:

let rec eval : type a. a expr -> a = function
| Value (Int i) -> i
| Value (Bool b) -> b
| Lt (a, b) -> (eval a) < (eval b)
| Gt (a, b) -> (eval a) > (eval b)
| Eq (a, b) -> (eval a) = (eval b)
| If (c, a, b) -> if eval c then (eval a) else (eval b)
;;

but got an error:

Line 4, characters 15-23:
Error: This expression has type $Lt_'a but an expression was expected of type
         int

What exactly does this mean?

Just to test further, I modified the expression GADT to be:

type _ expr =
| Value : 'a value -> 'a expr
| If : bool expr * 'a expr * 'a expr -> 'a expr
| Lt : int expr * int expr -> bool expr
| Eq : 'a expr * 'a expr -> bool expr
| Gt : int expr * int expr -> bool expr
;;

and then I see

Line 6, characters 15-23:
Error: This expression has type $Eq_'a but an expression was expected of type
         int

When I finally modify it to be

type _ expr =
| Value : 'a value -> 'a expr
| If : bool expr * 'a expr * 'a expr -> 'a expr
| Lt : int expr * int expr -> bool expr
| Eq : int expr * int expr -> bool expr
| Gt : int expr * int expr -> bool expr
;;

it works fine.

Update (more context):

  • Ocaml version: 4.08.1
  • Libraries opened during this session: Base

Update (solution):

  • it turned out to be (as mentioned in the first line of the selected answer) because I had previously, within utop run open Base;;
  • In a fresh session I'm able to enter the types initially mentioned and eval is happy with that.

The direct cause of the error is that you are using a library (maybe Base or Core?) that shadows the polymorphic comparison operators ( < , <= , = , >= , > ) and replace them with integer comparison operators.

Concerning the error message, when you pattern match a GADT constructor with existential types,

| Lt (a, b) -> (eval a) < (eval b)

the typechecker introduces new types to represent the existential types. Here, in the (original) definition of Lt ,

| Lt : 'a expr * 'a expr -> bool expr

there is one existentially quantified type variable: 'a .

When pattern matching on Lt , we need to replace this type variable with a new type. Moreover, it is quite useful in error message to try to pick a meaningful name for this type. To do so, the typechecker constructs a new type name piece by piece as $ + Lt + 'a :

  • $ : to mark an existential type
  • Lt : to indicate that it was introduced by the constructor Lt
  • a : to remember that the existential type variable was named 'a in the definition of the constructor

In other words, in the pattern match above, we have something akin to

| Lt ( (a: $Lt_'a eval), (b: $Lt_'a eval)) -> (eval a) < (eval b)

And when typing:

  (eval a) < (eval b)

the typechecker compare the type of < : int -> int with the type of eval a : $Lt_'a and outputs your original error message:

 Line 4, characters 15-23:
 Error: This expression has type $Lt_'a but an expression was expected of type
     int

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM