-
Notifications
You must be signed in to change notification settings - Fork 21
/
fundamentals_lecture.v
631 lines (456 loc) · 17.4 KB
/
fundamentals_lecture.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
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
(**
<<
Lecture 2: Fundamentals of Coq
-------------------------------------------------------------
Anders Mörtberg (Carnegie Mellon and Stockholm University)
Minor modifications made by Marco Maggesi (Univesity of Florence).
Minor modifications made by Niels van der Weide (Radboud University).
>>
The Coq proof assistant is a programming language for writing
proofs: https://coq.inria.fr/
It has been around since 1984 and was initially implemented by Thierry
Coquand and his PhD supervisor Gérard Huet. The first version, called
CoC, implemented the Calculus of Constructions as presented in:
"The Calculus of Constructions"
Thierry Coquand and Gérard Huet
Information and Computation 76(2–3): 95–120. 1988.
It was later extended to the Calculus of Inductive Constructions and
the name changed to Coq. These type theories are similar to Martin-Löf
type theory. As Coq is supposed to be a programming language for
developing proofs all programs have to be terminating, so it can be
seen as a "total" programming language.
The Coq system has a very long and detailed reference manual:
https://coq.inria.fr/distrib/current/refman/
However, UniMath is only using a small subset of Coq, so there is a
lot of information that is not relevant for UniMath development in
there. The fragment of Coq that UniMath uses consists of:
- Pi-types (with judgmental eta)
- Sigma-types (with judgmental eta)
- The inductive types of natural numbers, booleans, unit and empty
- Coproduct types
- A universe UU
The reason UniMath only relies on this subset is that everything in UniMath
has to be motivated by the model in simplicial sets:
https://arxiv.org/abs/1211.2851
In this lecture I will show some things than can be done in UniMath as
a programming language. In the later lectures we will also see how to
prove properties about the programs that we can write in UniMath.
The UniMath library can be found at:
https://github.com/UniMath/UniMath
This whole file is a Coq file and it hence has the file ending ".v" (v
for "vernacular") and can be processed using:
- emacs with proof-general: https://proofgeneral.github.io/
- Coq IDE
- VSCode
I use emacs as it is also an extremely powerful text editor, but if
you never saw emacs before it might be quite overwhelming. An
alternative that might be easier for newcomers is Coq IDE (interactive
development environment). It also has some features that emacs doesn't
have so some Coq experts use it as well, but in this talk I will use
emacs.
In order to make emacs interact with Coq one should install Proof
General. This is an extension to emacs that enables it to interact
with a range of proof assistants, including Coq. For UniMath
development one should also install agda-mode in order to be able to
properly insert unicode characters.
The basic keybinding that I use when working in Proof General are:
<<
C-c C-n -- Process one line
C-c C-u -- Unprocess a line
C-c C-ENTER -- Process the whole buffer up until the cursor
C-c C-b -- Process the whole file
C-c C-r -- Unprocess (retract) the whole file
C-x C-c -- Kill the Coq process
>>
For more commands see:
https://proofgeneral.github.io/doc/master/userman/Basic-Script-Management/#Script-processing-commands
https://proofgeneral.github.io/doc/master/userman/Coq-Proof-General/#Coq_002dspecific-commands
Here C = CTRL and M = ALT on a standard emacs setup, so "C-c C-n"
means "press c while holding CTRL and then press n while still holding
CTRL" (note that the keybindings are case sensitive). ENTER is the
"return" key on my keyboard.
Various basic emacs commands:
<<
C-x C-f -- Find file
C-x C-s -- Save file
C-x C-x -- Exit emacs
C-x b -- Kill buffer
C-_ -- Undo
C-x 1 -- Maximize buffer
C-x 2 -- Split buffer horizontally
C-x 3 -- Split buffer vertically
M-% -- Search-and-replace
M-; -- Comment region
>>
For more commands see: https://www.gnu.org/software/emacs/ (or just
Google "emacs tutorial")
*)
(** To import a file write:
<<
Require Import Dir.Filename.
>>
*)
(**
This will import the file Filename in the directory Dir. This assumes
that directory Dir is visible to Coq, that is, in the list of
directories in which Coq looks for files to import. If you are working
in the UniMath directory then Coq will be able to find all of the
files in the UniMath library, but if you are in another directory you
need to the update your LoadPath by running
<<
Add LoadPath "/path/to/UniMath".
>>
(where "/path/to/UniMath/" is replaced to the path where UniMath is
located on your computer).
Coq has a fancy module system which allows you to import and export
definitions in various complicated ways. We extremely rarely use
this in UniMath so you can safely ignore it for now. The only thing
you need to know is that there is an alternative to Require Import:
<<
Require Export Dir.Filename.
>>
that is used in some files. This will make the file you are working
on import all of the definitions in Dir.Filename and then export
them again so that any file that imports this file also gets the
definitions in Dir.Filename. I personally only use Require Import.
*)
(* Let's import one of the most basic UniMath file: *)
Require Import UniMath.Foundations.Preamble.
(* This file contains definition of the inductive types of UniMath,
makes UU the name for the universe and various other basic things. *)
(** * Definitions, lambda terms *)
(** The polymorphic identity function *)
Definition idfun : forall (A : UU), A -> A := fun (A : UU) (a : A) => a.
(** forall = Pi *)
(** fun = lambda *)
Check idfun. (* Or use Ctrl-Alt-C or Ctrl-Cmd-C on idfun. *)
Print idfun. (* Or use Ctrl-Alt-P or Ctrl-Cmd-P on idfun. *)
Definition idfun' (A : UU) (a : A) : A := a.
Check idfun'.
Print idfun'.
Definition idfun'' {A : UU} (a : A) : A := a.
Check idfun' nat 3.
(** The constant function that returns its first argument *)
Definition const (A B : UU) (a : A) (b : B) : A := a.
(** The booleans are defined in UniMath.Foundations.Preamble *)
About bool.
Print bool.
Locate bool.
(** These are generated by true and false *)
Check true.
Check false.
(** They also come with an induction principle *)
About bool_rect.
(*
bool_rect : ∏ P : bool → Type, P true → P false → ∏ b : bool, P b
*)
(** Using this we can define a "recursion" principle *)
Definition ifbool (A : UU) (x y : A) : bool -> A :=
bool_rect (fun _ : bool => A) x y.
(*
bool_rect (fun _ : bool => A) x y
P = fun _ : bool => A
x : P true [ A ]
y : P false [ A ]
b : bool
*)
(** We can define boolean negation: *)
Definition negbool : bool -> bool :=
ifbool bool false true.
Eval compute in negbool true.
(* Alternative definition using pattern matching.
Idiomatic in Coq, but we avoid doing this in UniMath. *)
Definition negbool' (b : bool) : bool :=
match b with
| true => false
| false => true
end.
(** The normalization of negbool and negbool' give the same term. *)
Eval compute in negbool.
Eval compute in negbool'.
Print bool_rect.
(** and compute with it *)
Eval compute in negbool true.
(** Coq supports many evaluation strategies, like cbn and cbv, for
details see:
https://coq.inria.fr/refman/tactics.html#Conversion-tactics
*)
(** boolean and *)
Definition andbool (b : bool) : bool -> bool :=
ifbool (bool -> bool) (idfun bool) (const bool bool false) b.
Definition andbool' (b1 b2 : bool) : bool
:= ifbool bool b2 false b1.
(*
if b1 is true
then b2
else false
*)
Eval compute in andbool' false true.
Eval compute in andbool' false false.
Eval compute in andbool' true false.
Eval compute in andbool' true true.
Eval compute in andbool true true.
Eval compute in andbool true false.
Eval compute in andbool false true.
Eval compute in andbool false false.
(** The natural numbers are defined in UniMath.Foundations.Preamble *)
About nat.
Print nat.
(** They are defined as Peano numbers, but we can use numerals *)
Check (S(S(S 0))).
Check 3.
(** This type also comes with an induction principle *)
Check nat_rect.
(** We can define the recursor: *)
Definition nat_rec (A : UU) (a : A) (f : nat -> A -> A) : nat -> A :=
nat_rect (fun _ : nat => A) a f.
(*
Definition nat_rec (A : UU) (a : A) (f : A -> A) : nat -> A :=
nat_rect (fun _ : nat => A) a f.
*)
(**
This can be understood as a function defined by the following clauses:
<<
nat_rec m f 0 = m
nat_rec m f (S n) = f n (nat_rec m f n)
>>
lecture 1 where f : A -> A
<<
nat_rec m f 0 = m
nat_rec m f (S n) = f (nat_rec m f n)
>>
*)
(** We can look at the normal form of the recursor by *)
Eval compute in nat_rec.
(** This contains a both a "fix" and "match _ with _". These primitives
of Coq are not allowed in UniMath. Instead we write everything using
recursors. The reason is that everything we write in UniMath has to be
justified by the simplicial set model and the situation for general
inductive types with match is not spelled out in detail. *)
(** If you are used to regular programming languages it might seem very
strange to only program with the recursors, but it's actually not too
bad and we can do many programs quite directly. *)
(** Truncated predecessor function *)
Definition pred : nat -> nat := nat_rec nat 0 (const nat nat).
Definition pred' : nat -> nat := nat_rec nat 0 (fun n m => n).
(*
<<
pred 0 = 0
pred (S n) = n
>>
*)
Eval compute in pred 3.
Eval compute in pred 1.
Eval compute in pred 0.
(** We can test if a number is even by: *)
Definition even : nat -> bool := nat_rec bool true (fun _ b => negbool b).
Eval compute in even 3.
Eval compute in even 4.
(** Addition *)
Definition add (m : nat) : nat -> nat := nat_rec nat m (fun _ y => S y).
Eval compute in add 2 3.
(** We can define a nice notation for addition by: *)
Notation "x + y" := (add x y).
Eval compute in 4 + 9.
Check (add 3 4). (* 3 + 4 : nat *)
(** To find information about a notation we can write: *)
Locate "+".
Locate add.
(** Coq allows us to write very sophisticated notations, for details
see: https://coq.inria.fr/refman/syntax-extensions.html *)
(** In UniMath we use a lot of unicode symbols. To input a unicode
symbol type \ and then the name of the symbol. For example \alpha
gives α. To get information about a unicode character, including
how to write it, put the cursor on top of the symbol and type:
M-x describe-char
We can write:
<<
λ x, e instead of fun x => e
∏ (x : A), T instead of forall (x : A), T
A → B instead of A -> B
>>
*)
(** Iterate a function n times *)
Definition iter (A : UU) (a : A) (f : A → A) (n : nat) : A :=
nat_rec A a (λ _ y, f y) n.
Notation "f ^ n" := (λ x, iter _ x f n).
Eval compute in (pred ^ 2) 5.
Definition sub (m n : nat) : nat := (pred ^ n) m.
Eval compute in sub 15 4.
Eval compute in sub 11 15.
Definition is_zero : nat → bool := nat_rec bool true (λ _ _, false).
Eval compute in is_zero 3.
Eval compute in is_zero 0.
Definition eqnat (m n : nat) : bool :=
andbool (is_zero (sub m n)) (is_zero (sub n m)).
Notation "m == n" := (eqnat m n) (at level 50).
Eval compute in 1 + 1 == 2.
Eval compute in 5 == 3.
Eval compute in 9 == 5.
(** Note that I could omit the A from the definition of f ̂ n and just
replace it by _. The reason is that Coq very often can infer what
arguments are so that we can omit them. *)
(** For example if I omit nat in *)
Check idfun _ 3.
(** Coq will figure it out for us. *)
(** We can tell Coq to always put _ for an argument by using curly
braces in the definition: *)
(** Such an argument is called an "implicit" and these are very useful
to get definitions that don't take too many arguments. However, it is
sometimes necessary to be able to give some of the arguments
explicitly, this is using "@". *)
Check @idfun'' nat 3.
(** * More inductive types *)
(** The inductive types we have seen so far come from the standard
library, but Coq allows us to define any inductive types we want. In
UniMath we don't allow this and the additional inductive types we have
are defined in Foundations. *)
(** One of these is the coproduct (disjoint union) of types *)
About coprod.
Print coprod.
Check ii1.
Check ii2.
Print inl.
Print inr.
Check (λ A B C : UU, @coprod_rect A B (λ _, C)).
Definition coprod_rec {A B C : UU} (f : A → C) (g : B → C) : coprod A B → C :=
@coprod_rect A B (λ _, C) f g.
(** We can define integers as a coproduct of nat with itself *)
Definition Z : UU := coprod nat nat.
(* NB: Use \hermitconjmatrix to type the symbol ⊹.
Use \minus to type the symbol − *)
Notation "⊹ x" := (inl x) (at level 20).
Notation "─ x" := (inr x) (at level 40).
(** +1 = inl 1 *)
(** 0 = inl 0 *)
(** -1 = inr 0 *)
(** Note that we get the negative numbers "off-by-one". *)
Definition Z1 : Z := ⊹ 1.
Definition Z0 : Z := ⊹ 0.
Definition Zn3 : Z := ─ 2.
(** We can define a function by case on whether the number is ⊹ n or ─ n *)
Definition Zcase (A : UU) (fpos : nat → A) (fneg : nat → A) : Z → A :=
coprod_rec fpos fneg.
Definition negate : Z → Z :=
Zcase Z (λ x, ifbool Z Z0 (─ pred x) (is_zero x)) (λ x, ⊹ S x).
Eval compute in negate Z0.
Eval compute in negate Z1.
Eval compute in negate Zn3.
(** We also have two more inductive types: *)
(** The unit type with one inhabitant tt *)
About unit.
Print unit.
(** The empty type with no inhabitants *)
About empty.
Print empty.
(** Terms as proofs. *)
(* Proof that true and false are different. *)
Require Import UniMath.Foundations.PartA.
(** Section's can be very useful to only write parameters that are used
many times once and for all. They are also useful for organizing your
files into logical sections. *)
Section True_not_False.
Variable (p : true = false).
Definition P : bool → UU :=
bool_rect _ unit ∅.
Definition true_eq_false_imp_empty : ∅ :=
(transportf P p tt).
End True_not_False.
About true_eq_false_imp_empty.
Definition true_not_false : true != false :=
true_eq_false_imp_empty.
(* Alternative definition, in one shot. *)
Definition true_not_false' : true != false :=
λ p, transportf (bool_rect _ unit ∅) p tt.
(* Normalization of the proof term. *)
Eval compute in true_not_false.
(** * Sigma types *)
(** Sigma types are called total2 and this is the only example of a
Record in the whole UniMath library. The reason we use a record is so
that we can get the eta principle definitionally. *)
About total2.
Print total2.
(** We have a notation ∑ (x : A), B for Sigma types *)
(** To form a pair use *)
Check tpair.
Locate ",,".
(** and to project out of a pair use *)
Check pr1.
Check pr2.
(** In PartA.v we define the direct product as a Sigma type *)
Definition dirprod (X Y : UU) : UU := ∑ x : X, Y.
Notation "A × B" := (dirprod A B) (at level 75, right associativity) : type_scope.
Definition dirprod_pr1 {X Y : UU} : X × Y → X := pr1.
Definition dirprod_pr2 {X Y : UU} : X × Y → Y := pr2.
Definition dirprodf {X Y X' Y' : UU} (f : X → Y) (f' : X' → Y')
(xx' : X × X') : Y × Y' := (f (pr1 xx'),,f' (pr2 xx')).
Definition swap {X Y : UU} (xy : X × Y) : Y × X :=
dirprodf dirprod_pr2 dirprod_pr1 (xy,,xy).
(** We can define the type of even numbers as a Sigma-type: *)
Definition even_nat : UU := ∑ (n : nat), ifbool _ unit empty (even n).
Print even_nat.
Definition test20 : even_nat := (20,,tt).
(** This Definition does not work *)
Fail Definition test3 : even_nat := (3,,tt).
Section curry.
Variables A B C : UU.
(** To make these arguments implicit use:
<<
Context {A B C : UU}.
>>
*)
Definition curry : (A × B → C) → (A → B → C) :=
λ (f : A × B → C) (a : A) (b : B), f (a,,b).
Definition uncurry : (A → B → C) → (A × B → C) :=
λ (f : A → B → C) (ab : A × B), f (pr1 ab) (pr2 ab).
End curry.
Check curry.
Print curry.
Check uncurry.
Print uncurry.
(** These were all the basics for interacting with Coq in this
lecture. The UniMath library is a very large library and so far we
have only seen parts of Preamble.v. When writing programs and proofs
in UniMath it is very important to be able to search the library so
that you don't do something someone else has already done. *)
(** To find everything about nat type: *)
Search nat.
(** To search for all lemmas involving the pattern *)
Search _ (_ -> _ -> _).
(** To find information about a notation *)
Locate "+".
(** More information about searching can be found in the reference
manual:
https://coq.inria.fr/distrib/current/refman/proof-engine/vernacular-commands.html?highlight=search#coq:cmd.search
*)
(**
One can also generate HTML documentation for UniMath that is a bit
easier to browse than reading text files. This is done by typing:
<<
> make html
>>
You can then open this documentation in your browser:
<<
> firefox html/toc.html
>>
In order to have your comments display properly in the HTML use the
following format:
(** This comment will be displayed *)
(** * This will be displayed as a section header *)
(** ** This will be a subsection *)
For more details see:
https://coq.inria.fr/distrib/current/refman/tools.html#coqdoc
*)
(**
The UniMath library is organized into a collection of packages that
can be found in the UniMath folder. The library is then compiled using
a Makefile which specifies in which order things has to be compiled
and how they should be compiled.
In order to have your file get compiled when you type "make" add it to
the .package/files file of the package where it belongs. See for
example: UniMath/UniMath/Foundations/.package/files
If you're working on a new package then you need to add it to the
Makefile by writing:
PACKAGES += MyPackage
*)
(*⋆⋆⋆⋆⋆⋆ THE END ⋆⋆⋆⋆⋆⋆*)