tek*_*agi 4 ocaml pattern-matching abstract-syntax-tree
我正在通过AST变换开发一种小型编程语言.也就是说,从VM开始并慢慢添加帮助程序员的层.
由于每个层都知道如何转换它的新类型,我做了类似这样的事情:
module AST0 = struct
type t = [
| `Halt
| `In
| `Out
| `Add of (int * int * int)
| `Sub of (int * int * int)
]
let lower (ast : t list) = ast
end
module AST1 = struct
type t = [
AST0.t
| `Inc of int
| `Dec of int
| `Cmp of (int * int * int)
]
let lower (ast : t list) =
let lower_one = function
| `Inc a -> [`Add (a, a, `Imm 1)]
| `Dec a -> [`Sub (a, a, `Imm 1)]
| `Cmp (a, b) -> [`Sub (13, a, b)]
| (x : AST0.t) -> AST0.lower [x] (* <--- problem line *)
in
List.concat @@ List.map lower_one ast
end
Run Code Online (Sandbox Code Playgroud)
不幸的是我得到了错误:
File "stackoverflow.ml", line 28, characters 8-20:
Error: This pattern matches values of type AST0.t
but a pattern was expected which matches values of type
[? `Cmp of 'a * 'b | `Dec of 'c | `Inc of 'd ]
The first variant type does not allow tag(s) `Cmp, `Dec, `Inc
Run Code Online (Sandbox Code Playgroud)
我想,因为编译器是足够聪明,我没有在任意匹配的情况下,它可以告诉大家,处理XY和Z变体x中AST1.lower绝不会实际上是一个Cmp或Inc或Dec.似乎并非如此.
我误解了OCaml的类型系统吗?我错过了一些明显的东西吗 这是一种愚蠢的方法吗?
您无法在本地约束案例模式的类型.类型约束也: AST0.t强制执行其他模式的类型AST0.t.这就是为什么你的代码没有打字检查; `Inc不包括在内AST0.t.
但是,OCaml中有一个简洁的功能,完全符合您的要求.使用#AST0.t模式别名,而不是类型约束.有关详细信息,请参阅https://caml.inria.fr/pub/docs/manual-ocaml/lablexamples.html#sec46:
(* I fixed several other trivial typing problems *)
let lower (ast : t list) =
let lower_one = function
| `Inc a -> [`Add (a, a, 1)]
| `Dec a -> [`Sub (a, a, 1)]
| `Cmp (a, b, c) -> [`Sub (13, a, b)]
| #AST0.t as x -> AST0.lower [x] (* <--- problem line *)
in
List.concat @@ List.map lower_one ast
Run Code Online (Sandbox Code Playgroud)
#AST0.t as x不仅是的缩写(`Halt | `In | `Out | `And _ | `Sub _ as x)而且改变的类型x中的右手侧->从[> AST1.t]到[> AST0.t].你可以在AST0.t那里使用它.