我在OCaml手册中看到这个例子使用GADT作为带功能应用的AST:
type _ term =
| Int : int -> int term
| Add : (int -> int -> int) term
| App : ('b -> 'a) term * 'b term -> 'a term
let rec eval : type a. a term -> a = function
| Int n -> n
| Add -> (fun x y -> x+y)
| App(f,x) -> (eval f) (eval x)
这是表示支持部分申请的语言不的功能应用程序的正确方法吗?
有没有办法让GADT支持具有任意数量参数的函数应用程序?
最后,GADT是表示类型化AST的好方法吗?还有其他选择吗?
答案 0 :(得分:2)
嗯,部分评估已在这里工作:
# eval (App(App(Add, Int 3),Int 4)) ;;
- : int = 7
# eval (App(Add, Int 3)) ;;
- : int -> int = <fun>
# eval (App(Add, Int 3)) 4 ;;
- : int = 7
你在这个小城市中没有的是抽象(lambdas),但绝对可以添加它。
如果您对该主题感兴趣,则会有大量(学术)文献。 This论文提供了支持部分评估的各种编码。
还有非Gadt解决方案,如this paper所示。
通常,GADT是表示评估者的一种非常有趣的方式。当你试图将AST转换为编译时,它们往往会有点短暂(但有ways)。
此外,您必须记住,您正在使用主机语言对您定义的语言的类型系统进行编码,这意味着您需要对所需类型功能进行编码。有时,这很棘手。
编辑:让GADT 不支持部分评估的方法是使用不包含函数的特殊值类型和具有函数的“功能值”类型。以第一篇论文的最简单表示形式,我们可以这样修改它:
type _ v =
| Int : int -> int v
| String : string -> string v
and _ vf =
| Base : 'a v -> ('a v) vf
| Fun : ('a vf -> 'b vf) -> ('a -> 'b) vf
and _ t =
| Val : 'a vf -> 'a t
| Lam : ('a vf -> 'b t) -> ('a -> 'b) t
| App : ('a -> 'b) t * 'a t -> 'b t
let get_val : type a . a v -> a = function
| Int i -> i
| String s -> s
let rec reduce : type a . a t -> a vf = function
| Val x -> x
| Lam f -> Fun (fun x -> reduce (f x))
| App (f, x) -> let Fun f = reduce f in f (reduce x)
let eval t =
let Base v = reduce t in get_val v
(* Perfectly defined expressions. *)
let f = Lam (fun x -> Lam (fun y -> Val x))
let t = App (f, Val (Base (Int 3)))
(* We can reduce t to a functional value. *)
let x = reduce t
(* But we can't eval it, it's a type error. *)
let y = eval t
(* HOF are authorized. *)
let app = Lam (fun f -> Lam (fun y -> App(Val f, Val y)))
根据您的需要,您可以根据需要更加复杂,重要的属性是'a v
类型无法生成函数。