我如何解释 OCaml 中的这个 GADT 错误?
How do I interpret this GADT error in OCaml?
抱歉 "what am I missing here" 问题的风格,但我在这里遗漏了一些东西。
我试图了解 GADT 在 OCaml 中的工作原理,我定义了以下内容(在 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
;;
我定义了一个eval
函数:
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)
;;
但出现错误:
Line 4, characters 15-23:
Error: This expression has type $Lt_'a but an expression was expected of type
int
这到底是什么意思?
为了进一步测试,我将表达式 GADT 修改为:
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
;;
然后我看到了
Line 6, characters 15-23:
Error: This expression has type $Eq_'a but an expression was expected of type
int
当我最后修改为
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
;;
它工作正常。
更新(更多上下文):
- Ocaml 版本:
4.08.1
- 在此 session 期间打开的图书馆:
Base
更新(解决):
- 原来是(选答案第一行提到的)因为我之前在
utop
运行open Base ;;
之内
- 在新的 session 中,我能够输入最初提到的类型,
eval
对此感到满意。
错误的直接原因是您使用的库(可能是 Base 或 Core?)隐藏了多态比较运算符(<
、<=
、=
、 >=
,>
) 并将它们替换为整数比较运算符。
关于错误消息,当您对具有存在类型的 GADT 构造函数进行模式匹配时,
| Lt (a, b) -> (eval a) < (eval b)
类型检查器引入了新类型来表示存在类型。
这里,在 Lt
、
的(原始)定义中
| Lt : 'a expr * 'a expr -> bool expr
有一个存在量化类型变量:'a
.
在Lt
上进行模式匹配时,我们需要将这个类型变量替换为
一种新类型。此外,在错误消息中尝试选择是非常有用的
这种类型的有意义的名称。为此,类型检查器构造了一个
一个接一个地命名为 $
+ Lt
+ 'a
:
$
: 标记存在类型
Lt
:表示由构造函数引入Lt
a
:要记住存在类型变量在构造函数的定义中被命名为'a
换句话说,在上面的模式匹配中,我们有类似于
的东西
| Lt ( (a: $Lt_'a eval), (b: $Lt_'a eval)) -> (eval a) < (eval b)
输入时:
(eval a) < (eval b)
类型检查器比较 <
的类型:int -> int
与 eval a
的类型:$Lt_'a
并输出原始错误消息:
Line 4, characters 15-23:
Error: This expression has type $Lt_'a but an expression was expected of type
int
抱歉 "what am I missing here" 问题的风格,但我在这里遗漏了一些东西。
我试图了解 GADT 在 OCaml 中的工作原理,我定义了以下内容(在 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
;;
我定义了一个eval
函数:
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)
;;
但出现错误:
Line 4, characters 15-23:
Error: This expression has type $Lt_'a but an expression was expected of type
int
这到底是什么意思?
为了进一步测试,我将表达式 GADT 修改为:
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
;;
然后我看到了
Line 6, characters 15-23:
Error: This expression has type $Eq_'a but an expression was expected of type
int
当我最后修改为
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
;;
它工作正常。
更新(更多上下文):
- Ocaml 版本:
4.08.1
- 在此 session 期间打开的图书馆:
Base
更新(解决):
- 原来是(选答案第一行提到的)因为我之前在
utop
运行open Base ;;
之内
- 在新的 session 中,我能够输入最初提到的类型,
eval
对此感到满意。
错误的直接原因是您使用的库(可能是 Base 或 Core?)隐藏了多态比较运算符(<
、<=
、=
、 >=
,>
) 并将它们替换为整数比较运算符。
关于错误消息,当您对具有存在类型的 GADT 构造函数进行模式匹配时,
| Lt (a, b) -> (eval a) < (eval b)
类型检查器引入了新类型来表示存在类型。
这里,在 Lt
、
| Lt : 'a expr * 'a expr -> bool expr
有一个存在量化类型变量:'a
.
在Lt
上进行模式匹配时,我们需要将这个类型变量替换为
一种新类型。此外,在错误消息中尝试选择是非常有用的
这种类型的有意义的名称。为此,类型检查器构造了一个
一个接一个地命名为 $
+ Lt
+ 'a
:
$
: 标记存在类型Lt
:表示由构造函数引入Lt
a
:要记住存在类型变量在构造函数的定义中被命名为'a
换句话说,在上面的模式匹配中,我们有类似于
的东西| Lt ( (a: $Lt_'a eval), (b: $Lt_'a eval)) -> (eval a) < (eval b)
输入时:
(eval a) < (eval b)
类型检查器比较 <
的类型:int -> int
与 eval a
的类型:$Lt_'a
并输出原始错误消息:
Line 4, characters 15-23:
Error: This expression has type $Lt_'a but an expression was expected of type
int