summaryrefslogtreecommitdiff
path: root/Test/hofs/Map.dfy
blob: a55be2be7f070bf40d666853e959df14664c4814 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117

datatype List<A> = Nil | Cons(hd: A,tl: List<A>);

function method Map<A,B>(f : A -> B, xs : List<A>) : List<B>
  requires forall x :: f.requires(x);
  reads *;
  decreases xs;
{
  match xs
    case Nil => Nil
    case Cons(x,xs) => Cons(f(x),Map(f,xs))
}

function method Id<A>(x : A) : A { x }

method Test() {
  assert Map(Id, Cons(1,Nil)) == Cons(1,Nil);
  var inc := x => x + 1;
  assert Map(inc, Cons(1,Nil)) == Cons(2,Nil);
  assert Map(x => x + 1, Cons(1,Nil)) == Cons(2,Nil);
  assert Map((x) requires x > 0 => x + 1, Nil) == Nil;
}

function CanCall<A,B>(f : A -> B, xs : List<A>) : bool
  decreases xs;
  reads *;
{
  match xs
    case Nil => true
    case Cons(x,xs) => f.requires(x) && CanCall(f, xs)
}

function method MegaMap<A,B>(f : A -> B, xs : List<A>) : List<B>
  requires CanCall(f, xs);
  reads *;
  decreases xs;
{
  match xs
    case Nil => Nil
    case Cons(x,xs) => Cons(f(x),MegaMap(f,xs))
}

method Test2() {
  assert MegaMap((x) requires x != 0 => 100 / x, Cons(2, Nil)).hd == 50;
}

function All<A>(p : A -> bool, xs : List<A>) : bool
  requires forall x :: p.requires(x) /* && p.reads(x) == {} */;
  reads *;
  decreases xs;
{
  match xs
    case Nil => true
    case Cons(x,xs) => p(x) && All(p,xs)
}

/*
function UnionMap(i : A -> set<B>, ys : List<A>): set<B>
  requires forall x :: i.requires(x) && i.reads(x) == {};
  decreases ys;
{
  match ys
    case Nil => {}
    case Cons(x,xs) => i(x) + UnionMap(i,xs)
}
*/

function method NinjaMap<A,B>(f : A -> B, ys : List<A>) : List<B>
  requires All(f.requires, ys);
//  reads UnionMap(f.reads, ys);
  reads *;
  decreases ys;
{
  match ys
    case Nil => Nil
    case Cons(x,xs) => Cons(f(x),NinjaMap(f,xs))
}

function method Compose(f : B -> C, g : A -> B) : A -> C
{
  x requires g.requires(x) && f.requires(g(x))
    reads    g.reads(x) + f.reads(g(x))
    => f(g(x))
}

lemma {:induction 0} MapCompose(f : B -> C, g : A -> B, xs : List<A>)
  requires All(g.requires, xs);
  requires All(f.requires, NinjaMap(g,xs));
  requires All(Compose(f,g).requires, xs);

  decreases xs;
  ensures NinjaMap(f,NinjaMap(g,xs)) == NinjaMap(Compose(f,g),xs);
{
  match xs
    case Nil =>
    case Cons(x,xs) =>
      calc {
            NinjaMap(f,NinjaMap(g,Cons(x,xs)));
         == NinjaMap(f,Cons(g(x),NinjaMap(g,xs)));
         == Cons(f(g(x)),NinjaMap(f,NinjaMap(g,xs)));
         == { MapCompose(f,g,xs); }
            Cons(f(g(x)),NinjaMap(Compose(f,g),xs));
         == Cons(Compose(f,g)(x),NinjaMap(Compose(f,g),xs));
         == NinjaMap(Compose(f,g),Cons(x,xs));
      }
}

// auto-mode
lemma MapCompose2(f : B -> C, g : A -> B, xs : List<A>)
  requires All(g.requires, xs);
  requires All(f.requires, NinjaMap(g,xs));
  requires All(Compose(f,g).requires, xs);
  decreases xs;
  ensures NinjaMap(f,NinjaMap(g,xs)) == NinjaMap(Compose(f,g),xs);
{
}