问题描述
我正在尝试编写一个在堆栈程序中执行布尔运算的函数。到目前为止,我已经得到了下面的代码,但是由于某种原因,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.
为什么会这样?无论我如何更改功能,我仍然收到它......有什么方法可以解决它吗? 谢谢!
解决方法
您有几个对 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 := ...
最后,作为未来问题的经验法则,请尽量减少您发布的示例,并确保它们具有重现您的问题所需的所有导入(例如 M.t
未定义,导入缺少 Z
和列表符号)。
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