无法猜测Coq中嵌套匹配的fix递减参数

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

怎么了 ?

Ant*_*nov 6

term是嵌套的归纳类型(由于list termFunc构造函数中),它经常需要一些额外的工作才能向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)