4 In Umberto Eco's "Foucault's Pendulum" (Il pendolo di Foucault,
5 1988), there is a short BASIC program that computes the 24
6 permutations of four letters. It is as follows:
9 20 INPUT L$(1), L$(2), L$(3), L$(4)
17 100 LET I4 = 10-(I1+I2+I3)
18 110 LPRINT L$(I1); L$(I2); L$(I3); L$(I4)
25 Note: In the French edition (Grasset, 2013), there is a typo
26 on line 80, with `=11` instead of `=I1`. And the dollar symbols
27 are replaced with the letter S.
29 I could not resist implementing it in WhyML and verifying it,
30 which is a simple, yet enjoyable, exercise.
32 Author: Jean-Christophe FilliĆ¢tre (CNRS)
40 (** A line printed on the output by the program is
41 a sequence of (4) integers. *)
44 (** The line `s` is a permutation of `1234`. *)
45 predicate perm4 (s: line) =
46 length s = 4 && (forall i. 0 <= i < 4 -> 1 <= s[i] <= 4) &&
49 (** The program outputs the permutations in lexicographic
50 order, so we introduce this order relation. *)
51 predicate lt (s1 s2: line) =
52 exists i. 0 <= i < 4 && s1[i] < s2[i] &&
53 forall j. 0 <= j < i -> s1[j] = s2[j]
56 forall s1 s2 s3. perm4 s1 -> perm4 s2 -> perm4 s3 ->
57 lt s1 s2 -> lt s2 s3 -> lt s1 s3
59 (** A sequence of lines contains only permutations
61 predicate sorted (o: seq line) =
62 (* only permutations *)
63 (forall j. 0 <= j < length o -> perm4 o[j]) &&
64 (* and they are sorted (and thus all distinct) *)
65 (forall j1 j2. 0 <= j1 < j2 < length o -> lt o[j1] o[j2])
67 (** A sequence of lines is sorted and contains exactly
68 the permutations satisfying predicate `pr`. *)
69 predicate below (o: seq line) (pr: line -> bool) =
71 (forall j. 0 <= j < length o -> pr o[j]) &&
72 (forall s. perm4 s -> pr s -> mem s o)
74 (** Shortcut predicates for the loop invariants below: *)
75 function pr1 (i1: int) : line->bool = fun s ->
77 function pr2 (i1 i2: int) : line->bool = fun s ->
78 pr1 i1 s || s[0]=i1 && s[1]<i2
79 function pr3 (i1 i2 i3: int) : line->bool = fun s ->
80 pr2 i1 i2 s || s[0]=i1 && s[1]=i2 && s[2]<i3
82 (** The output of the program is modeled with the
83 following global variable that contains a sequence
85 val ref output: seq line
87 let anagrammi () : unit
88 requires { output = empty }
89 ensures { below output (fun _ -> true) }
91 invariant { below output (pr1 i1) }
93 invariant { below output (pr2 i1 i2) }
94 if i2 = i1 then continue;
96 invariant { below output (pr3 i1 i2 i3) }
97 if i3 = i1 then continue;
98 if i3 = i2 then continue;
99 let i4 = 10 - (i1+i2+i3) in
100 (* LPRINT L$(I1); L$(I2); L$(I3); L$(I4) *)
101 let line = cons i1 (cons i2 (cons i3 (cons i4 empty))) in
102 assert { line[0] = i1 && line[1] = i2 &&
103 line[2] = i3 && line[3] = i4 };
104 assert { perm4 line };
105 output <- snoc output line