2

Dafny makes use of a decreases clause to verify that a recursive function terminates. When verification fails can Dafny be given a hint, in this case in the form of a lemma. How to I tell Dafny to use the lemma when checking that the decreases clause actually decreases?

datatype List<T> = Nil | Cons(head:T, tail:List<T>) 
datatype Twee = Node(value : int, left : Twee, right : Twee) | Leaf
function rotateLeft(t:Twee) :Twee
{
    match t 
       case Leaf => t 
       case Node(v,Node(vl,ll,rl),r) => Node(vl,ll,Node(v,rl,r))
       case Node(v,Leaf,r) => Node(v,Leaf,r)
}
  function Leftheight(t:Twee) :(h:nat) decreases t
{
  match t 
    case Leaf => 0 
    case Node(_,l,_) =>  1+Leftheight(l)
}     
lemma {:induction ll, rl, r} decreasesHint(v:int, vl:int, ll:Twee,rl:Twee,r:Twee)
   ensures   Leftheight(Node(v,Node(vl,ll,rl),r)) == 
           1+ Leftheight(Node(vl,ll, Node(v,rl,r)))  {} 
function rotateAllLeft(t:Twee) :Twee
    decreases t, Leftheight(t)
{
    match t 
       case Leaf => Leaf 
       case Node(v,Leaf,r) => Node(v,Leaf,rotateAllLeft(r))  //decrases t
       case Node(v,Node(vl,ll,rl),r) => //{ decreasesHint(v,vl,ll,rl,r);}
                  rotateAllLeft(rotateLeft(Node(v,Node(vl,ll,rl),r)))     
}

Sorry for such a long example but this is the first time I have wanted to give hints for checking termination. The error failure to decrease termination measure occurs on the last line rotateAllLeft(rotateLeft(Node(v,Node(vl,ll,rl),r).

david streader
  • 589
  • 2
  • 7

1 Answers1

0

You can call a lemma from inside an expression. Just use a semicolon to separate the lemma call from the rest of the expression.

      case Node(v,Node(vl,ll,rl),r) =>
        decreasesHint(v,vl,ll,rl,r);
        rotateAllLeft(rotateLeft(Node(v,Node(vl,ll,rl),r)))

Note that this does not completely solve your termination problems, because your decreases annotation is t, Leftheight(t), which means that recursive calls must either make t smaller, or leave t the same and make the left height smaller. But this recursive call does not leave t the same. I tried changing your annotation to just decreases Leftheight(t), which accepted this case, but gave an error on the previous case. Maybe you can find a way around that.

James Wilcox
  • 5,307
  • 16
  • 25