зеркало из
https://github.com/iharh/notes.git
synced 2025-10-30 13:16:07 +02:00
218 строки
7.8 KiB
Plaintext
218 строки
7.8 KiB
Plaintext
(** We can make numerical expressions a little easier to read and
|
|
write by introducing "notations" for addition, multiplication, and
|
|
subtraction. *)
|
|
|
|
Notation "x + y" := (plus x y) (at level 50, left associativity) : nat_scope.
|
|
Notation "x - y" := (minus x y) (at level 50, left associativity) : nat_scope.
|
|
Notation "x * y" := (mult x y) (at level 40, left associativity) : nat_scope.
|
|
|
|
Check ((0 + 1) + 1).
|
|
|
|
(** Note that these do not change the definitions we've already
|
|
made: they are simply instructions to the Coq parser to accept [x
|
|
+ y] in place of [plus x y] and, conversely, to the Coq
|
|
pretty-printer to display [plus x y] as [x + y].
|
|
|
|
Each notation-symbol in Coq is active in a _notation scope_. Coq
|
|
tries to guess what scope you mean, so when you write [S(O*O)] it
|
|
guesses [nat_scope], but when you write the cartesian
|
|
product (tuple) type [bool*bool] it guesses [type_scope].
|
|
Occasionally you have to help it out with percent-notation by
|
|
writing [(x*y)%nat], and sometimes in Coq's feedback to you it
|
|
will use [%nat] to indicate what scope a notation is in.
|
|
|
|
Notation scopes also apply to numeral notation (3,4,5, etc.), so you
|
|
may sometimes see [0%nat] which means [O], or [0%Z] which means the
|
|
Integer zero. *)
|
|
|
|
|
|
Notation "( x , y )" := (pair x y).
|
|
|
|
|
|
|
|
(** As with pairs, it is more convenient to write lists in
|
|
familiar programming notation. The following two declarations
|
|
allow us to use [::] as an infix [cons] operator and square
|
|
brackets as an "outfix" notation for constructing lists. *)
|
|
|
|
Notation "x :: l" := (cons x l) (at level 60, right associativity).
|
|
Notation "[ ]" := nil.
|
|
Notation "[ x , .. , y ]" := (cons x .. (cons y nil) ..).
|
|
|
|
(** It is not necessary to fully understand these declarations,
|
|
but in case you are interested, here is roughly what's going on.
|
|
|
|
The [right associativity] annotation tells Coq how to parenthesize
|
|
expressions involving several uses of [::] so that, for example,
|
|
the next three declarations mean exactly the same thing: *)
|
|
|
|
Definition l_123' := 1 :: (2 :: (3 :: nil)).
|
|
Definition l_123'' := 1 :: 2 :: 3 :: nil.
|
|
Definition l_123''' := [1,2,3].
|
|
|
|
(** The [at level 60] part tells Coq how to parenthesize
|
|
expressions that involve both [::] and some other infix operator.
|
|
For example, since we defined [+] as infix notation for the [plus]
|
|
function at level 50,
|
|
[[
|
|
Notation "x + y" := (plus x y)
|
|
(at level 50, left associativity).
|
|
]]
|
|
The [+] operator will bind tighter than [::], so [1 + 2 :: [3]]
|
|
will be parsed, as we'd expect, as [(1 + 2) :: [3]] rather than [1
|
|
+ (2 :: [3])].
|
|
|
|
(By the way, it's worth noting in passing that expressions like "[1
|
|
+ 2 :: [3]]" can be a little confusing when you read them in a .v
|
|
file. The inner brackets, around 3, indicate a list, but the outer
|
|
brackets are there to instruct the "coqdoc" tool that the bracketed
|
|
part should be displayed as Coq code rather than running text.
|
|
These brackets don't appear in the generated HTML.)
|
|
|
|
The second and third [Notation] declarations above introduce the
|
|
standard square-bracket notation for lists; the right-hand side of
|
|
the third one illustrates Coq's syntax for declaring n-ary
|
|
notations and translating them to nested sequences of binary
|
|
constructors. *)
|
|
|
|
|
|
|
|
|
|
(** Actually, [app] will be used a lot in some parts of what
|
|
follows, so it is convenient to have an infix operator for it. *)
|
|
|
|
Notation "x ++ y" := (app x y)
|
|
(right associativity, at level 60).
|
|
|
|
|
|
(* ###################################################### *)
|
|
(** *** Implicit Arguments *)
|
|
|
|
(** If fact, we can go further. To avoid having to sprinkle [_]'s
|
|
throughout our programs, we can tell Coq _always_ to infer the
|
|
type argument(s) of a given function. *)
|
|
|
|
Implicit Arguments nil [[X]].
|
|
Implicit Arguments cons [[X]].
|
|
Implicit Arguments length [[X]].
|
|
Implicit Arguments app [[X]].
|
|
Implicit Arguments rev [[X]].
|
|
Implicit Arguments snoc [[X]].
|
|
|
|
(** We can also declare an argument to be implicit while
|
|
defining the function itself, by surrounding the argument in curly
|
|
braces. For example: *)
|
|
|
|
Fixpoint length'' {X:Type} (l:list X) : nat :=
|
|
match l with
|
|
| nil => 0
|
|
| cons h t => S (length'' t)
|
|
end.
|
|
|
|
(** One small problem with declaring arguments [Implicit] is
|
|
that, occasionally, Coq does not have enough local information to
|
|
determine a type argument; in such cases, we need to tell Coq that
|
|
we want to give the argument explicitly this time, even though
|
|
we've globally declared it to be [Implicit]. For example, if we
|
|
write: *)
|
|
|
|
(* Definition mynil := nil. *)
|
|
|
|
(** If we uncomment this definition, Coq will give us an error,
|
|
because it doesn't know what type argument to supply to [nil]. We
|
|
can help it by providing an explicit type declaration (so that Coq
|
|
has more information available when it gets to the "application"
|
|
of [nil]): *)
|
|
|
|
Definition mynil : list nat := nil.
|
|
|
|
(** Alternatively, we can force the implicit arguments to be explicit by
|
|
prefixing the function name with [@]. *)
|
|
|
|
Check @nil.
|
|
|
|
Definition mynil' := @nil nat.
|
|
|
|
(** Using argument synthesis and implicit arguments, we can
|
|
define convenient notation for lists, as before. Since we have
|
|
made the constructor type arguments implicit, Coq will know to
|
|
automatically infer these when we use the notations. *)
|
|
|
|
Notation "x :: y" := (cons x y)
|
|
(at level 60, right associativity).
|
|
Notation "[ ]" := nil.
|
|
Notation "[ x , .. , y ]" := (cons x .. (cons y []) ..).
|
|
Notation "x ++ y" := (app x y)
|
|
(at level 60, right associativity).
|
|
|
|
(** Now lists can be written just the way we'd hope: *)
|
|
|
|
Definition list123''' := [1, 2, 3].
|
|
|
|
(* ###################################################### *)
|
|
(** ** Polymorphic Pairs *)
|
|
|
|
(** Following the same pattern, the type definition we gave in
|
|
the last chapter for pairs of numbers can be generalized to
|
|
_polymorphic pairs_ (or _products_): *)
|
|
|
|
Inductive prod (X Y : Type) : Type :=
|
|
pair : X -> Y -> prod X Y.
|
|
|
|
Implicit Arguments pair [[X] [Y]].
|
|
|
|
(** As with lists, we make the type arguments implicit and define the
|
|
familiar concrete notation. *)
|
|
|
|
Notation "( x , y )" := (pair x y).
|
|
|
|
(** We can also use the [Notation] mechanism to define the standard
|
|
notation for pair _types_: *)
|
|
|
|
Notation "X * Y" := (prod X Y) : type_scope.
|
|
|
|
(** (The annotation [: type_scope] tells Coq that this abbreviation
|
|
should be used when parsing types. This avoids a clash with the
|
|
multiplication symbol.) *)
|
|
|
|
(** A note of caution: it is easy at first to get [(x,y)] and
|
|
[X*Y] confused. Remember that [(x,y)] is a _value_ consisting of a
|
|
pair of values; [X*Y] is a _type_ consisting of a pair of types. If
|
|
[x] has type [X] and [y] has type [Y], then [(x,y)] has type [X*Y]. *)
|
|
|
|
(** The first and second projection functions now look pretty
|
|
much as they would in any functional programming language. *)
|
|
|
|
Definition fst {X Y : Type} (p : X * Y) : X :=
|
|
match p with (x,y) => x end.
|
|
|
|
Definition snd {X Y : Type} (p : X * Y) : Y :=
|
|
match p with (x,y) => y end.
|
|
|
|
(** The following function takes two lists and combines them
|
|
into a list of pairs. In many functional programming languages,
|
|
it is called [zip]. We call it [combine] for consistency with
|
|
Coq's standard library. *)
|
|
(** Note that the pair notation can be used both in expressions and in
|
|
patterns... *)
|
|
|
|
Fixpoint combine {X Y : Type} (lx : list X) (ly : list Y)
|
|
: list (X*Y) :=
|
|
match (lx,ly) with
|
|
| ([],_) => []
|
|
| (_,[]) => []
|
|
| (x::tx, y::ty) => (x,y) :: (combine tx ty)
|
|
end.
|
|
|
|
(** Indeed, when no ambiguity results, we can even drop the enclosing
|
|
parens: *)
|
|
|
|
Fixpoint combine' {X Y : Type} (lx : list X) (ly : list Y)
|
|
: list (X*Y) :=
|
|
match lx,ly with
|
|
| [],_ => []
|
|
| _,[] => []
|
|
| x::tx, y::ty => (x,y) :: (combine' tx ty)
|
|
end.
|
|
|