Coq:无法猜测 fix 的递减参数

Coq: Cannot guess decreasing argument of fix

我正在尝试编写一个在堆栈程序中执行布尔运算的函数。到目前为止,我已经得到了下面的代码,但是由于某种原因,executeBool 不起作用。 Coq 显示错误“无法猜测修复的递减参数”,但我不太确定为什么,因为它看起来有点“明显” program.

Require Import ZArith.
Require Import List.
Require Import Recdef.
Require Import Coq.FSets.FMaps.
Require Import Coq.Strings.String.

Module Import M := FMapList.Make(String_as_OT). 

Set Implicit Arguments.
Open Scope Z_scope. 
Open Scope string_scope.

Inductive insStBool : Type :=
  | SBPush    : Z -> insStBool
  | SBLoad    : string -> insStBool
  | SBNeg     : insStBool
  | SBCon     : insStBool
  | SBDis     : insStBool
  | SBEq      : insStBool
  | SBLt      : insStBool
  | SBSkip    : nat -> insStBool.

Definition getVal (s:string) (st:M.t Z) : Z := 
  match (find s st) with 
    | Some val => val
    | None     => 0
  end.

Fixpoint executeBool (state:M.t Z) (stack:list Z) (program:list insStBool) : list Z :=
  match program with 
    | nil              => stack
    | (SBPush n)::l    => executeBool state (n::stack) l
    | (SBLoad x)::l    => executeBool state ((getVal x state)::stack) l
    | (SBNeg)::l       => match stack with 
                            | nil   => nil
                            | 0::st => executeBool state (1::st) l
                            | _::st => executeBool state (0::st) l
                          end
    | (SBCon)::(SBSkip n)::l  => match stack with 
                                      | nil   => nil 
                                      | 0::st => executeBool state (0::st) ((SBSkip n)::l)
                                      | _::st => executeBool state st l
                                 end
    | (SBDis)::(SBSkip n)::l  => match l with 
                                  | nil  => nil
                                  | m::k =>
                                    match stack with 
                                      | nil   => nil 
                                      | 0::st => executeBool state st l
                                      | _::st => executeBool state (1::st) ((SBSkip n)::l)
                                    end
                                 end
    | (SBSkip n)::m::l => match n with 
                            | 0%nat => executeBool state stack (m::l)
                            | (S k) => executeBool state stack ((SBSkip k)::l)
                          end
    | (SBEq)::l        => match stack with 
                            | nil      => nil 
                            | n::nil   => nil 
                            | n::m::st => match (m - n) with 
                                            | 0 => executeBool state (1::st) l
                                            | _ => executeBool state (0::st) l
                                          end
                          end  
    | (SBLt)::l        => match stack with 
                            | nil      => nil 
                            | n::nil   => nil 
                            | n::m::st => match (m - n) with 
                                            | Z.pos x => executeBool state (1::st) l
                                            | _       => executeBool state (0::st) l
                                          end
                          end
    | _ => nil
    end.

为什么会这样?无论我如何更改功能,我都会得到它......有什么办法可以解决它吗? 谢谢!

program 在技术上是递减的,但你在语法上使用它时添加了一个构造函数,Coq 的递减检查不是很聪明。尝试为匹配中的子元素命名 as 并使用此名称:

    | (SBCon)::((SBSkip n)::l as l') => match stack with 
                                      | nil   => nil 
                                      | 0::st => executeBool state (0::st) (l')
                                      | _::st => executeBool state st l

您有一些对 executeBool 的递归调用,它们不是直接在程序的子项上调用,而是在您从子项重建的项上调用,例如 executeBool state (0::st) ((SBSkip n)::l)。解决方案是明确 (SBSkip n)::l 是程序的一个子项,方法是用 as 子句捕获相应的匹配案例

match program with
...
| (SBCon)::(((SBSkip n)::l) as l')  => ... executeBool state (0::st) l'
...

为了了解 Coq 哪里有问题,您还可以在定义中添加一个明确的 struct 子句以指示应该减少哪个参数(它还可以通过较大的固定点带来更好的性能) :

Fixpoint executeBool (state:M.t Z) (stack:list Z) (program:list insStBool) {struct program} : list Z := ...

最后,作为未来问题的经验法则,请尽量减少您 post 的示例,并确保它们具有重现您的问题所需的所有导入(例如 M.t未定义,缺少 Z 和列表符号的导入)。