对于我编写的一些代码,我正在尝试使用OCaml 中的可组合错误处理中的技术(带有错误多态变体的结果类型)。我尝试使用的函数类型如下所示:
val parse : parser -> token list -> (Nominal.term, [> `ParseError of string ]) Result.t
val lex : lexer -> string -> (token list, [> `LexError of string ]) Result.t
我尝试编写它们是这样的:
let lex_and_parse
: parser -> lexer -> string -> (Nominal.term, [> `ParseError of string | `LexError of string ]) Result.t
= fun parser lexer input ->
let open Result.Let_syntax in
let%bind tokens = lex lexer input in
parse parser tokens
不幸的是,编译器(4.09.0)报告了一个类型错误:
File "src/Pratt.ml", line 147, characters 4-23:
147 | parse parser tokens
^^^^^^^^^^^^^^^^^^^
Error: This expression has type
(Nominal.term, [ `ParseError of string ]) result
but an expression was expected of type
(Nominal.term, [> `LexError of string ]) result
The first variant type does not allow tag(s) `LexError
请注意,如果我手动执行等效操作,则代码会编译:
let lex_and_parse
: parser -> lexer -> string -> (Nominal.term, [> `ParseError of string | `LexError of string ]) Result.t
= fun parser lexer input ->
match lex lexer input with
| Error (`LexError err) -> Error (`LexError err)
| Ok tokens ->
(match parse parser tokens with
| Ok result -> Ok result
| Error (`ParseError err) -> Error (`ParseError err))
实际上,这并不完全正确。等效的是这个,它也无法编译(以相同的方式):
match lex lexer input with
| Error err -> Error err
| Ok tokens ->
match parse parser tokens with
| Ok result -> Ok result
| Error err -> Error err
File "src/Pratt.ml", line 155, characters 29-32:
155 | | Error err -> Error err
^^^
Error: This expression has type [ `ParseError of string ]
but an expression was expected of type
[> `LexError of string | `ParseError of string ]
The first variant type does not allow tag(s) `LexError
所以我的问题是这个。请注意,错误消息显示“此表达式具有类型(Nominal.term, [ `ParseError of string ]) result
”。这是我不明白的——我从来没有在任何地方指定那种类型,事实上,这两个地方ParseError
都提到了,它有一个>
约束。那么这种类型是从哪里来的呢?IE [>
ParseError of string ] become
[在ParseError of string ]
哪里?
还:
- 我的尝试和 Vladimir 的原版(我假设它是编译的)有什么区别?
- 有没有办法将多态变体从
[ x ]
to弱化[> x ]
?(除了手动将所有标签从第一种类型映射到第二种类型)
编辑:
我上传了所有的上下文代码。
编辑2(对不起):
我做了一些探索并提出了这个实现:
let parse : parser -> token list -> (Nominal.term, [> `ParseError of string ]) Result.t
= fun parser toks ->
match expression parser toks with
(* | [], result -> result *)
(* | _, Error err -> Error err *)
| _, Ok _ -> Error (`ParseError "leftover tokens")
| _, _ -> Error (`ParseError "unimplemented")
如果我删除任何一条注释行,则执行lex_and_parse
再次开始失败。编译并且它的类型签名永远不会改变对我来说有点令人不安parse
,但是调用者可能无法进行类型检查。这怎么可能?这种非局部效应严重违反了我对类型检查/签名(应该)如何工作的期望。我真的很想了解发生了什么。