[英]Asserted precondition might not hold in mutual inductive Dafny lemmas
我正在嘗試使用記錄交互的樹來證明 Dafny 中具有副作用的程序的語義,遵循自由單子方法。 因此,語義將產生以下形狀的樹(簡化為僅用於讀取輸入的一條指令)。
datatype Prog<A>
= Return (pure : A)
| Get(input : string -> Prog<A>)
主要問題是這些是無限分支的樹,在 Dafny 中使用這些樹需要一些技巧,因為它們對深度沒有限制,盡管每片葉子都可以通過有限的路徑到達。
我現在想做的是將大步語義定義為歸納關系, 請參閱文章《Dafny 中的有根據的函數和極限謂詞:教程》 。 這是語言的一小部分,只有一個用於閱讀的命令和一個用於命令的順序組合。 關系big_step_bind
依次組成兩個交互樹(bind 是組成單子計算的映射的常用術語),而big_step
是大步語義關系。 這些關系是歸納和相互定義的。
datatype Com = GetC | SeqC(Com, Com)
type Store = map<int, string>
least predicate big_step_bind(c : Com, p : Prog<Store>, q : Prog<Store>) {
match p {
case Return(s) => big_step(c, s, q)
case Get(f) => exists g :: q == Get(g) && forall i :: big_step_bind(c, f(i), g(i))
}
}
least predicate big_step(c : Com, s : Store, p : Prog<Store>) {
match c {
case GetC =>
p == Get(i => Return(s[0 := i]))
case SeqC(c1, c2) =>
exists p1 :: big_step(c1, s, p1) && big_step_bind(c2, p1, p)
}
}
到目前為止,一切都運作良好。 但是要在生成的交互樹上運行任何函數,我需要知道大步語義只提供有根據的樹,因為 Dafny 不允許通過對Prog
進行遞歸定義並抱怨不終止。 因此,我定義了一個謂詞wfTree
,它挑選出所有類型為Prog
的有根據的樹,實際上應該是所有這些樹。
least predicate wfTree<A> (p : Prog<A>){
match p {
case Return(b) => true
case Get(g) => forall x :: wfTree(g(x))
}
}
現在我想證明大步語義“產生”的所有樹都是有根據的:
least lemma big_step_bind_wf(c : Com, p : Prog<Store>, q : Prog<Store>)
requires wfTree(p) // (1)
requires big_step_bind(c, p, q)
ensures wfTree(q)
{
match p {
case Return(s) => big_step_wf(c, s, q);
case Get(f) =>
var i ;
var q' :| big_step_bind(c, f(i), q');
big_step_bind_wf(c, f(i), q');
}
}
least lemma big_step_wf(c : Com, s : Store, p : Prog<Store>)
requires big_step(c, s, p)
ensures wfTree(p)
{
match c {
case GetC => return;
case SeqC(c1, c2) =>
var p1 :| big_step(c1, s, p1) && big_step_bind(c2, p1, p);
big_step_wf(c1, s, p1); // (2)
assert wfTree(p1); // (3)
big_step_bind_wf(c2, p1, p); // (4)
}
}
同樣,這些引理通過歸納相互證明。 但是,證明的最后一步(4)無法驗證。 達芙妮 說
錯誤:此調用的先決條件可能不成立。
並且指的是(1),這是big_step_bind_wf
的前提條件,需要wfTree(p1)
保持。 然而,(2) 恰好具有作為后置條件,並且 (3) 處的assert
顯示了這一點。
我現在的問題是:為什么 Dafny 不能確定前提條件是否成立? 我是否遺漏了什么或者這是實施的問題? 非常感謝!
我能夠通過將有根據的程序前置條件移動到后置條件(至少是綁定的引理)來驗證。
datatype Program<T> = Result(T) | Get(input: string -> Program<T>)
datatype Command = GetInput | Sequence(Command, Command)
least predicate big_step_bind
(c: Command,
p1: Program<string>,
p2: Program<string>)
{
match p1 {
case Result(x) => big_step(c, p2)
case Get(pr) =>
exists qr :: p2 == Get(qr)
&& forall i :: big_step_bind(c, pr(i), qr(i))
}
}
least predicate big_step(c: Command, p: Program<string>){
match c {
case GetInput => p == Get(input => Result(input))
case Sequence(c1, c2) =>
exists p1 :: big_step(c1, p1) && big_step_bind(c2, p1, p)
}
}
least predicate wellFoundedProgram(p: Program<string>)
{
match p {
case Result(x) => true
case Get(px) => forall i :: wellFoundedProgram(px(i))
}
}
least lemma wellFoundedGenerationBind(c: Command, p1: Program<string>, p: Program<string>)
requires big_step_bind(c, p1, p)
ensures wellFoundedProgram(p1)
ensures wellFoundedProgram(p)
{
match p1 {
case Result(x) => { wellFoundedGeneration(c, p) ;}
case Get(px) => {
}
}
}
least lemma wellFoundedGeneration(c: Command, p: Program<string>)
requires big_step(c, p)
ensures wellFoundedProgram(p)
{
match c {
case GetInput => {}
case Sequence(c1, c2) => {
var p1 :| big_step(c1, p1) && big_step_bind(c2, p1, p);
wellFoundedGenerationBind(c2, p1, p);
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.