考虑以下无类型lambda演算的玩具表示:
Require Import String.
Open Scope string_scope.
Inductive term : Set :=
| Var : string -> term
| Abs : string -> term -> term
| App : term -> term -> term.
Fixpoint print (term : term) :=
match term return string with
| Var id => id
| Abs id term => "\" ++ id ++ " " ++ print term
| App term1 term2 => print_inner term1 ++ " " ++ print_inner term2
end
with print_inner (term : term) :=
match term return string with
| Var id => id
| term => "(" ++ print term ++ ")"
end.
类型检查print
失败,并显示以下错误:
Recursive definition of print_inner is ill-formed.
[...]
Recursive call to print has principal argument equal to "term" instead of "t".
实现这一目标的最具可读性/符合人体工程学/效率的方法是什么?
答案 0 :(得分:2)
您可以使用嵌套递归函数:
Fixpoint print (tm : term) : string :=
match tm return string with
| Var id => id
| Abs id body => "\" ++ id ++ ". " ++ print body
| App tm1 tm2 =>
let fix print_inner (tm : term) : string :=
match tm return string with
| Var id => id
| _ => "(" ++ print tm ++ ")"
end
in
print_inner tm1 ++ " " ++ print_inner tm2
end.
这种方法可以扩展到处理漂亮打印 - 通常的惯例是不要在x y z
等表达式中打印括号(左边的应用程序关联)或打印\x. \y. x y
{{1} }:
\xy. x y
顺便说一句,CPDT在相互递归与嵌套递归上有some material,但是在不同的设置中。
答案 1 :(得分:2)
您也可以通过print_inner
执行的案例分析来解除递归调用的想法,如下所示:
Definition print_inner (term : term) (sterm : string) : string :=
match term with
| Var id => id
| _ => "(" ++ sterm ++ ")"
end.
Fixpoint print (term : term) :=
match term return string with
| Var id => id
| Abs id term => "\" ++ id ++ " " ++ print term
| App term1 term2 => print_inner term1 (print term1)
++ " " ++ print_inner term2 (print term2)
end.
或者,您可以使用不同的算法,依赖于构造函数的固定级别来决定是否忽略括号。