Bor*_* E. 5 functional-programming coq totality
我对术语有以下定义:
Inductive term : Type :=
| Var : variable -> term
| Func : function_symbol -> list term -> term.
Run Code Online (Sandbox Code Playgroud)
一个函数,该函数pos_list获取术语列表并为每个子术语返回“位置”列表。例如,对于[Var "e"; Func "f" [Var "x"; Func "i" [Var "x"]]]我来说,应该知道[[1]; [2]; [2; 1]; [2; 2]; [2; 2; 1]]每个元素在子项的树层次结构中的位置。
Definition pos_list (args:list term) : list position :=
let fix pos_list_aux ts is head :=
let enumeration := enumerate ts in
let fix post_enumeration ts is head :=
match is with
| [] => []
| y::ys =>
let new_head := (head++y) in
match ts with
| [] => []
| (Var _)::xs => [new_head] ++ (post_enumeration xs ys head)
| (Func _ args')::xs =>
[new_head] ++
(pos_list_aux args' [] new_head) ++
(post_enumeration xs ys head)
end
end
in post_enumeration ts enumeration head
in pos_list_aux args [] [].
Run Code Online (Sandbox Code Playgroud)
有了上面的代码,我得到了错误
错误:无法猜测减少的参数
fix
在第一种let fix结构上,但在我看来,对(pos_list_aux args' [] new_head)(导致问题)的调用以参数为参数args',而子项(Func _ args')本身就是的子项ts。
怎么了 ?
term是嵌套的归纳类型(由于list term在Func构造函数中),它经常需要一些额外的工作才能向Coq解释您的函数是完整的。CPDT的这一章介绍了如何处理这种情况(请参见“嵌套归纳类型”部分):
术语“嵌套归纳类型”暗示了此特定问题的解决方案。就像互归类型需要相互递归的归纳原理一样,嵌套类型也需要嵌套递归。
这是我为您解决问题的尝试。首先,让我们添加一些导入和定义,以便所有内容都能编译:
Require Import Coq.Lists.List.
Import ListNotations.
Require Import Coq.Strings.String.
Require Import Coq.Strings.Ascii.
Definition variable := string.
Definition function_symbol := string.
Definition position := list nat.
Inductive term : Type :=
| Var : variable -> term
| Func : function_symbol -> list term -> term.
Run Code Online (Sandbox Code Playgroud)
我们首先实现一个功能来完成单个操作term。注意,我们定义了一个嵌套函数pos_list_many_aux,它几乎就是您最初想要的:
Definition pos_list_one (i : nat) (t : term) : list position :=
let fix pos_list_one_aux (i : nat) (t : term) {struct t} : list position :=
match t with
| Var _ => [[i]]
| Func _ args =>
[i] :: map (cons i)
((fix pos_list_many_aux i ts :=
match ts with
| [] => []
| t::ts =>
pos_list_one_aux i t ++ pos_list_many_aux (S i) ts
end) 1 args). (* hardcoded starting index *)
end
in pos_list_one_aux i t.
Run Code Online (Sandbox Code Playgroud)
现在,我们将需要一个辅助功能mapi(命名自OCaml的stdlib)。就像一样map,但是映射函数还接收当前列表元素的索引。
Definition mapi {A B : Type} (f : nat -> A -> B) (xs : list A) : list B :=
let fix mapi i f xs :=
match xs with
| [] => []
| x::xs => (f i x) :: mapi (S i) f xs
end
in mapi 0 f xs.
Run Code Online (Sandbox Code Playgroud)
现在,一切准备就绪,可以定义pos_list函数了:
Definition pos_list (args : list term) : list position :=
concat (mapi (fun i t => pos_list_one (S i) t) args).
Run Code Online (Sandbox Code Playgroud)
让我们运行测试:
Section Test.
Open Scope string_scope.
Compute pos_list [Var "e"; Func "f" [Var "x"; Func "i" [Var "x"]]].
(*
= [[1]; [2]; [2; 1]; [2; 2]; [2; 2; 1]] : list position
*)
End Test.
Run Code Online (Sandbox Code Playgroud)