-
Notifications
You must be signed in to change notification settings - Fork 46
/
general_recursion.v
189 lines (150 loc) · 8.03 KB
/
general_recursion.v
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
(** * General recursive functions
This file explores a way to formalize general recursive functions
without worrying about termination proofs, counters or monads.
The definitions are actually defined by well-founded recursion on the
total relation (which isn't well-founded). Using fueling of the
accessibility proof, we can however compute with these definitions
inside Coq and reason on them independently of the termination
proof. *)
(* begin hide *)
(** printing elimination %\coqdoctac{elimination}% *)
(** printing noconf %\coqdoctac{noconf}% *)
(** printing simp %\coqdoctac{simp}% *)
(** printing by %\coqdockw{by}% *)
(** printing rec %\coqdockw{rec}% *)
(** printing Coq %\Coq{}% *)
(** printing funelim %\coqdoctac{funelim}% *)
(** printing Derive %\coqdockw{Derive}% *)
(** printing Signature %\coqdocclass{Signature}% *)
(** printing Subterm %\coqdocclass{Subterm}% *)
(** printing NoConfusion %\coqdocclass{NoConfusion}% *)
From Equations Require Import Equations.
Require Import ZArith Lia.
Require Import Program.
Require Import Psatz.
Require Import Nat.
Require Import Stdlib.Vectors.VectorDef.
Require Import Relations.
Set Keyed Unification.
Set Equations Transparent.
(* end hide *)
(** The total relation. *)
Definition total_relation {A : Type} : A -> A -> Prop := fun x y => True.
(** We assume an inconsistent axiom here, one should be added function per function. *)
Axiom wf_total_init : forall {A}, WellFounded (@total_relation A).
#[local]
Remove Hints wf_total_init : typeclass_instances.
(** We fuel it with some Acc_intro constructors so that definitions relying on it
can unfold a fixed number of times still. *)
#[local]
Instance wf_total_init_compute : forall {A}, WellFounded (@total_relation A).
exact (fun A => Acc_intro_generator 10 wf_total_init).
Defined.
(** Now we define an obviously non-terminating function. *)
Equations? nonterm (n : nat) : nat by wf n (@total_relation nat) :=
nonterm 0 := 0;
nonterm (S n) := S (nonterm (S n)).
Proof.
(* Every pair of arguments is in the total relation: so
[total_relation (S n) (S n)] *) red.
constructor.
Defined.
Local Obligation Tactic := idtac.
(** The automation has a little trouble here as it assumes
well-founded definitions implicitely. We show the second
equation: [nonterm (S n) = S (nonterm (S n))] using the
unfolding equation. *)
Next Obligation.
intros. now rewrite nonterm_unfold_eq at 1.
Defined.
(* Note this is a dangerous rewrite rule, so we should remove it from the hints *)
(* Print Rewrite HintDb nonterm. *)
(** Make nonterm transparent anyway so we can compute with it *)
Transparent nonterm.
(** We can compute with it (for closed natural numbers) *)
Definition at_least_five (n : nat) : bool :=
match n with
| S (S (S (S (S x)))) => true
| _ => false
end.
Transparent wf_total_init_compute.
(** Indeed it unfolds enough so that [at_least_five] gives back a result. *)
Example check_10 := eq_refl : at_least_five (nonterm 10) = true.
Example check_0 := eq_refl : at_least_five (nonterm 0) = false.
(** The elimination principle completely abstracts away from the
termination argument as well *)
Lemma nonterm_ge n : n <= nonterm n.
Proof.
funelim (nonterm n).
reflexivity.
lia.
Defined.
(** We can go as far as defining the (call-by-name) Y combinator and computing with it. *)
Section Y.
Context {A : Type}.
Equations? Y (f : A -> A) : A by wf f (@total_relation (A -> A)) :=
Y f := f (Y f).
Proof.
(* Every pair of arguments is in the total relation: so
[total_relation f f] *) red. constructor.
Defined.
Obligation Tactic := idtac.
(** The automation has a little trouble here as it assumes
well-founded definitions implicitely. We show the second
equation: [nonterm (S n) = S (nonterm (S n))] using the
unfolding equation. *)
Next Obligation.
intros. now rewrite Y_unfold_eq at 1.
Defined.
End Y.
(** Using [Y], we can easily define any general recursive function. *)
Definition fact :=
Y (fun (fact : nat -> nat) (x : nat) =>
match x with
| 0 => 1
| S n => S n * fact n
end).
Check eq_refl : fact 8 = 40320.
(** [Y] is only good in call-by-name or call-by-need, so we switch to Haskell *)
Extraction Language Haskell.
Recursive Extraction fact.
(*
y :: (a1 -> a1) -> a1
y x =
x (y x)
fact :: Nat -> Nat
fact =
y (\fact0 x -> case x of {
O -> S O;
S n -> mul (S n) (fact0 n)})
*)
(** Let's define an efficient version whose termination is not entirely obvious. *)
Definition factN :=
Y (fun (fact : N -> N) (x : N) =>
match x with
| N0 => 1%N
| Npos n => (Npos n * fact (Pos.pred_N n))%N
end).
(** [1001!] is pretty large. *)
Definition fact1001 :=
402789647337170867317246136356926989705094239074925347176343710340368450911027649612636252695456374205280468598807393254690298539867803367460225153499614535588421928591160833678742451354915921252299285456946271396995850437959540645019696372741142787347450281325324373824456300226871609431497826989489109522725791691167945698509282421538632966523376679891823696900982075223188279465194065489111498586522997573307838057934994706212934291477882221464914058745808179795130018969175605739824237247684512790169648013778158661520384916357285547219660337504067910087936301580874662367543921288988208261944834178369169805682489420504038334529389177845089679546075023305854006141256288633820079940395329251563788399404652902154519302928365169452383531030755684578503851488154092323576150311569325891190105926118761607100286827930472944913272420825078912158741589850136017030887975452922434889688775883386977825215904423682478943313806072144097432418695807412571292308739802481089407002523955080148184062810447564594783139830113821372260474145316521647368313934670783858482781506915288378941348078689691815657785305896912277993200639858696294199549107738635599538328374931258525869323348477334798827676297868823693023377418942304272267800509765805435653787530370118261219994752588866451072715583785495394684524593296728611334955079882857173250037068541860372512693170819259309411027837176612444692649174536429745421086287708588130082168792750697158901737130221751430550976429258055277255676893874108456870904122902259417224707137723406125811549952159629766771063079472679280213882978523785424760309678138268708239764925768714349554665438389311198715040908077757086900159389712443987670244241787904585093011546861502058550090914877900852701619648229332192401075747543562989953271508977501771085759521631427816116191761031257454497039673414248149210836002497114107565960458576525212556159634975715552638678172137468172843066451093984443636560722213668172225585711566558134467392654185460222589723312097599987253417831473939565071006344352518096564427781204200068323913056897090916602712260306869786107237077572445866572945760977721639408338430009976028970539150822336553856613962747814621747092348996915755983464741082000337526945990059365493439921937093368896754791416759604324895514660325913157843796039917819613717350380997781225472000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000%N.
(** We can still compute with our [Y] combinator *)
Time Check (@eq_refl _ (fact1001) <: factN 1001 = fact1001).
(** It takes [0.8sec] using [vm_compute]. *)
(** An alternative is to use the total relation directly. *)
Equations factN' (n : N) : N by wf n (@total_relation N) :=
| N0 => 1;
| Npos n => (Npos n * factN' (Pos.pred_N n)).
Next Obligation. constructor. Defined.
(** Unsurprisingly, this computes just as well *)
Time Check (@eq_refl _ (fact1001) <: factN' 1001 = fact1001).
(** It takes [0.8sec] using [vm_compute] as well. *)
(** [factN'] also makes sense in a strict/call-by-value language like OCaml. *)
Extraction Language OCaml.
Extraction factN'.
(*
(** val factN' : n -> n **)
let rec factN' = function
| N0 -> Npos XH
| Npos p -> N.mul (Npos p) (let y = Pos.pred_N p in factN' y)
*)