// RUN: %dafny /compile:3 "%s" > "%t"
// RUN: %diff "%s.expect" "%t"
datatype List = Nil | Cons(head: A,tail: List)
datatype Tree = Branch(val: A,trees: List>)
function ListData(xs : List) : set
ensures forall x :: x in ListData(xs) ==> x < xs
{
match xs
case Nil => {}
case Cons(x,xs) => {x} + ListData(xs)
}
function TreeData(t0 : Tree) : set
ensures forall t :: t in TreeData(t0) ==> t < t0
{
var Branch(x,ts) := t0;
{x} + set t, y | t in ListData(ts) && y in TreeData(t) :: y
}
function Pre(f : A -> B, s : set) : bool
reads (set x, y | x in s && y in f.reads(x) :: y)
{
forall x :: x in s ==> f.reads(x) == {} && f.requires(x)
}
function method Map(xs : List, f : A -> B): List
reads Pre.reads(f, ListData(xs))
requires Pre(f, ListData(xs))
decreases xs
{
match xs
case Nil => Nil
case Cons(x,xs) => Cons(f(x),Map(xs,f))
}
function method TMap(t0 : Tree, f : A -> B) : Tree
reads Pre.reads(f, TreeData(t0))
requires Pre(f, TreeData(t0))
decreases t0
{
var Branch(x,ts) := t0;
Branch(f(x),Map(ts, t requires t in ListData(ts)
requires Pre(f, TreeData(t))
=> TMap(t,f)))
}
method Main()
{
var t := TMap(Branch(1,Cons(Branch(2,Nil),Nil)), x requires x != 0 => 100 / x);
assert t == Branch(100,Cons(Branch(50,Nil),Nil));
print t, "\n";
}