Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
C
cpdt
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
research
cpdt
Commits
cffeeacc
Commit
cffeeacc
authored
Nov 09, 2009
by
Adam Chlipala
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Ported Subset
parent
70f53dbb
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
75 additions
and
68 deletions
+75
-68
Makefile
Makefile
+3
-1
Subset.v
src/Subset.v
+72
-67
No files found.
Makefile
View file @
cffeeacc
...
...
@@ -38,7 +38,9 @@ latex/cpdt.tex: Makefile $(VS)
-o
../latex/cpdt.tex
latex/%.tex
:
src/%.v
coqdoc
--interpolate
--latex
-s
$<
-o
$@
coqdoc
--interpolate
--latex
-s
\
-p
"
\u
sepackage{url}"
\
$<
-o
$@
latex/%.dvi
:
latex/%.tex
cd
latex
;
latex
$*
;
latex
$*
...
...
src/Subset.v
View file @
cffeeacc
...
...
@@ -28,16 +28,16 @@ Set Implicit Arguments.
(
**
Let
us
consider
several
ways
of
implementing
the
natural
number
predecessor
function
.
We
start
by
displaying
the
definition
from
the
standard
library
:
*
)
Print
pred
.
(
**
[[
(
**
%
\
vspace
{-
.15
in
}%
[[
pred
=
fun
n
:
nat
=>
match
n
with
|
0
=>
0
|
S
u
=>
u
end
:
nat
->
nat
]]
*
)
]]
(
**
We
can
use
a
new
command
,
[
Extraction
]
,
to
produce
an
OCaml
version
of
this
function
.
*
)
We
can
use
a
new
command
,
[
Extraction
]
,
to
produce
an
OCaml
version
of
this
function
.
*
)
Extraction
pred
.
...
...
@@ -64,35 +64,35 @@ Lemma zgtz : 0 > 0 -> False.
Qed
.
Definition
pred_strong1
(
n
:
nat
)
:
n
>
0
->
nat
:=
match
n
return
(
n
>
0
->
nat
)
with
match
n
with
|
O
=>
fun
pf
:
0
>
0
=>
match
zgtz
pf
with
end
|
S
n
'
=>
fun
_
=>
n
'
end
.
(
**
We
expand
the
type
of
[
pred
]
to
include
a
%
\
textit
{%
#
<
i
>
#
proof
#
</
i
>
#
%}%
that
its
argument
[
n
]
is
greater
than
0.
When
[
n
]
is
0
,
we
use
the
proof
to
derive
a
contradiction
,
which
we
can
use
to
build
a
value
of
any
type
via
a
vacuous
pattern
match
.
When
[
n
]
is
a
successor
,
we
have
no
need
for
the
proof
and
just
return
the
answer
.
The
proof
argument
can
be
said
to
have
a
%
\
textit
{%
#
<
i
>
#
dependent
#
</
i
>
#
%}%
type
,
because
its
type
depends
on
the
%
\
textit
{%
#
<
i
>
#
value
#
</
i
>
#
%}%
of
the
argument
[
n
]
.
There
are
two
aspects
of
the
definition
of
[
pred_strong1
]
that
may
be
surprising
.
First
,
we
took
advantage
of
[
Definition
]
'
s
syntactic
sugar
for
defining
function
arguments
in
the
case
of
[
n
]
,
but
we
bound
the
proofs
later
with
explicit
[
fun
]
expressions
.
Second
,
there
is
the
[
return
]
clause
for
the
[
match
]
,
which
we
saw
briefly
in
Chapter
2.
Let
us
see
what
happens
if
we
write
this
function
in
the
way
that
at
first
seems
most
natural
.
*
)
One
aspects
in
particular
of
the
definition
of
[
pred_strong1
]
that
may
be
surprising
.
We
took
advantage
of
[
Definition
]
'
s
syntactic
sugar
for
defining
function
arguments
in
the
case
of
[
n
]
,
but
we
bound
the
proofs
later
with
explicit
[
fun
]
expressions
.
Let
us
see
what
happens
if
we
write
this
function
in
the
way
that
at
first
seems
most
natural
.
(
**
[[
[[
Definition
pred_strong1
'
(
n
:
nat
)
(
pf
:
n
>
0
)
:
nat
:=
match
n
with
|
O
=>
match
zgtz
pf
with
end
|
S
n
'
=>
n
'
end
.
[[
Error:
In
environment
n
:
nat
pf
:
n
>
0
The
term
"pf"
has
type
"n > 0"
while
it
is
expected
to
have
type
"0 > 0"
]]
The
term
[
zgtz
pf
]
fails
to
type
-
check
.
Somehow
the
type
checker
has
failed
to
take
into
account
information
that
follows
from
which
[
match
]
branch
that
term
appears
in
.
The
problem
is
that
,
by
default
,
[
match
]
does
not
let
us
use
such
implied
information
.
To
get
refined
typing
,
we
must
always
add
special
[
match
]
annotations
.
The
term
[
zgtz
pf
]
fails
to
type
-
check
.
Somehow
the
type
checker
has
failed
to
take
into
account
information
that
follows
from
which
[
match
]
branch
that
term
appears
in
.
The
problem
is
that
,
by
default
,
[
match
]
does
not
let
us
use
such
implied
information
.
To
get
refined
typing
,
we
must
always
rely
on
[
match
]
annotations
,
either
written
explicitly
or
inferred
.
In
this
case
,
we
must
use
a
[
return
]
annotation
to
declare
the
relationship
between
the
%
\
textit
{%
#
<
i
>
#
value
#
</
i
>
#
%}%
of
the
[
match
]
discriminee
and
the
%
\
textit
{%
#
<
i
>
#
type
#
</
i
>
#
%}%
of
the
result
.
There
is
no
annotation
that
lets
us
declare
a
relationship
between
the
discriminee
and
the
type
of
a
variable
that
is
already
in
scope
;
hence
,
we
delay
the
binding
of
[
pf
]
,
so
that
we
can
use
the
[
return
]
annotation
to
express
the
needed
relationship
.
W
hy
does
Coq
not
infer
this
relationship
for
us
?
Certainly
,
it
is
not
hard
to
imagine
heuristics
that
would
handle
this
particular
case
and
many
others
.
In
general
,
however
,
the
inference
problem
is
undecidable
.
The
known
undecidable
problem
of
%
\
textit
{%
#
<
i
>
#
higher
-
order
unification
#
</
i
>
#
%}%
reduces
to
the
[
match
]
type
inference
problem
.
Over
time
,
Coq
is
enhanced
with
more
and
more
heuristics
to
get
around
this
problem
,
but
there
must
always
exist
[
match
]
es
whose
types
Coq
cannot
infer
without
annotations
.
W
e
are
lucky
that
Coq
'
s
heuristics
infer
the
[
return
]
clause
(
specifically
,
[
return
n
>
0
->
nat
])
for
us
in
this
case
.
In
general
,
however
,
the
inference
problem
is
undecidable
.
The
known
undecidable
problem
of
%
\
textit
{%
#
<
i
>
#
higher
-
order
unification
#
</
i
>
#
%}%
reduces
to
the
[
match
]
type
inference
problem
.
Over
time
,
Coq
is
enhanced
with
more
and
more
heuristics
to
get
around
this
problem
,
but
there
must
always
exist
[
match
]
es
whose
types
Coq
cannot
infer
without
annotations
.
Let
us
now
take
a
look
at
the
OCaml
code
Coq
generates
for
[
pred_strong1
]
.
*
)
...
...
@@ -119,12 +119,12 @@ let pred_strong1 = function
We
can
reimplement
our
dependently
-
typed
[
pred
]
based
on
%
\
textit
{%
#
<
i
>
#
subset
types
#
</
i
>
#
%}%,
defined
in
the
standard
library
with
the
type
family
[
sig
]
.
*
)
Print
sig
.
(
**
[[
(
**
%
\
vspace
{-
.15
in
}%
[[
Inductive
sig
(
A
:
Type
)
(
P
:
A
->
Prop
)
:
Type
:=
exist
:
forall
x
:
A
,
P
x
->
sig
P
For
sig
:
Argument
A
is
implicit
For
exist
:
Argument
A
is
implicit
]]
[
sig
]
is
a
Curry
-
Howard
twin
of
[
ex
]
,
except
that
[
sig
]
is
in
[
Type
]
,
while
[
ex
]
is
in
[
Prop
]
.
That
means
that
[
sig
]
values
can
survive
extraction
,
while
[
ex
]
proofs
will
always
be
erased
.
The
actual
details
of
extraction
of
[
sig
]
s
are
more
subtle
,
as
we
will
see
shortly
.
...
...
@@ -132,8 +132,7 @@ For exist: Argument A is implicit
We
rewrite
[
pred_strong1
]
,
using
some
syntactic
sugar
for
subset
types
.
*
)
Locate
"{ _ : _ | _ }"
.
(
**
[[
(
**
%
\
vspace
{-
.15
in
}%
[[
Notation
Scope
"{ x : A | P }"
:=
sig
(
fun
x
:
A
=>
P
)
:
type_scope
...
...
@@ -171,10 +170,10 @@ We can continue on in the process of refining [pred]'s type. Let us change its
Definition
pred_strong3
(
s
:
{
n
:
nat
|
n
>
0
}
)
:
{
m
:
nat
|
proj1_sig
s
=
S
m
}
:=
match
s
return
{
m
:
nat
|
proj1_sig
s
=
S
m
}
with
|
exist
0
pf
=>
match
zgtz
pf
with
end
|
exist
(
S
n
'
)
_
=>
exist
_
n
'
(
refl_equal
_
)
|
exist
(
S
n
'
)
pf
=>
exist
_
n
'
(
refl_equal
_
)
end
.
(
**
The
function
[
proj1_sig
]
extracts
the
base
value
from
a
subset
type
.
Besides
the
use
of
that
function
,
the
only
other
new
thing
is
the
use
of
the
[
exist
]
constructor
to
build
a
new
[
sig
]
value
,
and
the
details
of
how
to
do
that
follow
from
the
output
of
our
earlier
[
Print
]
command
.
(
**
The
function
[
proj1_sig
]
extracts
the
base
value
from
a
subset
type
.
Besides
the
use
of
that
function
,
the
only
other
new
thing
is
the
use
of
the
[
exist
]
constructor
to
build
a
new
[
sig
]
value
,
and
the
details
of
how
to
do
that
follow
from
the
output
of
our
earlier
[
Print
]
command
.
It
also
turns
out
that
we
need
to
include
an
explicit
[
return
]
clause
here
,
since
Coq
'
s
heuristics
are
not
smart
enough
to
propagate
the
result
type
that
we
wrote
earlier
.
By
now
,
the
reader
is
probably
ready
to
believe
that
the
new
[
pred_strong
]
leads
to
the
same
OCaml
code
as
we
have
seen
several
times
so
far
,
and
Coq
does
not
disappoint
.
*
)
...
...
@@ -200,34 +199,32 @@ We have managed to reach a type that is, in a formal sense, the most expressive
Definition
pred_strong4
(
n
:
nat
)
:
n
>
0
->
{
m
:
nat
|
n
=
S
m
}.
refine
(
fun
n
=>
match
n
return
(
n
>
0
->
{
m
:
nat
|
n
=
S
m
}
)
with
match
n
with
|
O
=>
fun
_
=>
False_rec
_
_
|
S
n
'
=>
fun
_
=>
exist
_
n
'
_
end
)
.
(
*
begin
thide
*
)
(
**
We
build
[
pred_strong4
]
using
tactic
-
based
proving
,
beginning
with
a
[
Definition
]
command
that
ends
in
a
period
before
a
definition
is
given
.
Such
a
command
enters
the
interactive
proving
mode
,
with
the
type
given
for
the
new
identifier
as
our
proof
goal
.
We
do
most
of
the
work
with
the
[
refine
]
tactic
,
to
which
we
pass
a
partial
"proof"
of
the
type
we
are
trying
to
prove
.
There
may
be
some
pieces
left
to
fill
in
,
indicated
by
underscores
.
Any
underscore
that
Coq
cannot
reconstruct
with
type
inference
is
added
as
a
proof
subgoal
.
In
this
case
,
we
have
two
subgoals
:
[[
2
subgoals
n
:
nat
_
:
0
>
0
============================
False
]]
[[
subgoal
2
is
:
S
n
'
=
S
n
'
]]
We
can
see
that
the
first
subgoal
comes
from
the
second
underscore
passed
to
[
False_rec
]
,
and
the
second
subgoal
comes
from
the
second
underscore
passed
to
[
exist
]
.
In
the
first
case
,
we
see
that
,
though
we
bound
the
proof
variable
with
an
underscore
,
it
is
still
available
in
our
proof
context
.
It
is
hard
to
refer
to
underscore
-
named
variables
in
manual
proofs
,
but
automation
makes
short
work
of
them
.
Both
subgoals
are
easy
to
discharge
that
way
,
so
let
us
back
up
and
ask
to
prove
all
subgoals
automatically
.
*
)
Undo
.
refine
(
fun
n
=>
match
n
return
(
n
>
0
->
{
m
:
nat
|
n
=
S
m
}
)
with
match
n
with
|
O
=>
fun
_
=>
False_rec
_
_
|
S
n
'
=>
fun
_
=>
exist
_
n
'
_
end
)
;
crush
.
...
...
@@ -237,8 +234,7 @@ Defined.
(
**
We
end
the
"proof"
with
[
Defined
]
instead
of
[
Qed
]
,
so
that
the
definition
we
constructed
remains
visible
.
This
contrasts
to
the
case
of
ending
a
proof
with
[
Qed
]
,
where
the
details
of
the
proof
are
hidden
afterward
.
Let
us
see
what
our
proof
script
constructed
.
*
)
Print
pred_strong4
.
(
**
[[
(
**
%
\
vspace
{-
.15
in
}%
[[
pred_strong4
=
fun
n
:
nat
=>
match
n
as
n0
return
(
n0
>
0
->
{
m
:
nat
|
n0
=
S
m
}
)
with
...
...
@@ -254,6 +250,7 @@ match n as n0 return (n0 > 0 -> {m : nat | n0 = S m}) with
exist
(
fun
m
:
nat
=>
S
n
'
=
S
m
)
n
'
(
refl_equal
(
S
n
'
))
end
:
forall
n
:
nat
,
n
>
0
->
{
m
:
nat
|
n
=
S
m
}
]]
We
see
the
code
we
entered
,
with
some
proofs
filled
in
.
The
first
proof
obligation
,
the
second
argument
to
[
False_rec
]
,
is
filled
in
with
a
nasty
-
looking
proof
term
that
we
can
be
glad
we
did
not
enter
by
hand
.
The
second
proof
obligation
is
a
simple
reflexivity
proof
.
...
...
@@ -265,27 +262,39 @@ Notation "[ e ]" := (exist _ e _).
Definition
pred_strong5
(
n
:
nat
)
:
n
>
0
->
{
m
:
nat
|
n
=
S
m
}.
refine
(
fun
n
=>
match
n
return
(
n
>
0
->
{
m
:
nat
|
n
=
S
m
}
)
with
match
n
with
|
O
=>
fun
_
=>
!
|
S
n
'
=>
fun
_
=>
[
n
'
]
end
)
;
crush
.
Defined
.
(
**
One
other
alternative
is
worth
demonstrating
.
Recent
Coq
versions
include
a
facility
called
[
Program
]
that
streamlines
this
style
of
definition
.
Here
is
a
complete
implementation
using
[
Program
]
.
*
)
Obligation
Tactic
:=
crush
.
Program
Definition
pred_strong6
(
n
:
nat
)
(
_
:
n
>
0
)
:
{
m
:
nat
|
n
=
S
m
}
:=
match
n
with
|
O
=>
_
|
S
n
'
=>
n
'
end
.
(
**
Printing
the
resulting
definition
of
[
pred_strong6
]
yields
a
term
very
similar
to
what
we
built
with
[
refine
]
.
[
Program
]
can
save
time
in
writing
programs
that
use
subset
types
.
Nonetheless
,
[
refine
]
is
often
just
as
effective
,
and
[
refine
]
gives
you
more
control
over
the
form
the
final
term
takes
,
which
can
be
useful
when
you
want
to
prove
additional
theorems
about
your
definition
.
[
Program
]
will
sometimes
insert
type
casts
that
can
complicate
theorem
-
proving
.
*
)
(
**
*
Decidable
Proposition
Types
*
)
(
**
There
is
another
type
in
the
standard
library
which
captures
the
idea
of
program
values
that
indicate
which
of
two
propositions
is
true
.
*
)
Print
sumbool
.
(
**
[[
(
**
%
\
vspace
{-
.15
in
}%
[[
Inductive
sumbool
(
A
:
Prop
)
(
B
:
Prop
)
:
Set
:=
left
:
A
->
{
A
}
+
{
B
}
|
right
:
B
->
{
A
}
+
{
B
}
For
left
:
Argument
A
is
implicit
For
right
:
Argument
B
is
implicit
]]
*
)
]]
(
**
We
can
define
some
notations
to
make
working
with
[
sumbool
]
more
convenient
.
*
)
We
can
define
some
notations
to
make
working
with
[
sumbool
]
more
convenient
.
*
)
Notation
"'Yes'"
:=
(
left
_
_
)
.
Notation
"'No'"
:=
(
right
_
_
)
.
...
...
@@ -296,8 +305,8 @@ Notation "'Reduce' x" := (if x then Yes else No) (at level 50).
Now
we
can
write
[
eq_nat_dec
]
,
which
compares
two
natural
numbers
,
returning
either
a
proof
of
their
equality
or
a
proof
of
their
inequality
.
*
)
Definition
eq_nat_dec
(
n
m
:
nat
)
:
{
n
=
m
}
+
{
n
<>
m
}.
refine
(
fix
f
(
n
m
:
nat
)
{
struct
n
}
:
{
n
=
m
}
+
{
n
<>
m
}
:=
match
n
,
m
return
{
n
=
m
}
+
{
n
<>
m
}
with
refine
(
fix
f
(
n
m
:
nat
)
:
{
n
=
m
}
+
{
n
<>
m
}
:=
match
n
,
m
with
|
O
,
O
=>
Yes
|
S
n
'
,
S
m
'
=>
Reduce
(
f
n
'
m
'
)
|
_
,
_
=>
No
...
...
@@ -386,10 +395,9 @@ Section In_dec.
(
**
The
final
function
is
easy
to
write
using
the
techniques
we
have
developed
so
far
.
*
)
Definition
In_dec
:
forall
(
x
:
A
)
(
ls
:
list
A
)
,
{
In
x
ls
}
+
{
~
In
x
ls
}.
refine
(
fix
f
(
x
:
A
)
(
ls
:
list
A
)
{
struct
ls
}
:
{
In
x
ls
}
+
{
~
In
x
ls
}
:=
match
ls
return
{
In
x
ls
}
+
{
~
In
x
ls
}
with
Definition
In_dec
:
forall
(
x
:
A
)
(
ls
:
list
A
)
,
{
In
x
ls
}
+
{~
In
x
ls
}.
refine
(
fix
f
(
x
:
A
)
(
ls
:
list
A
)
:
{
In
x
ls
}
+
{~
In
x
ls
}
:=
match
ls
with
|
nil
=>
No
|
x
'
::
ls
'
=>
A_eq_dec
x
x
'
||
f
x
ls
'
end
)
;
crush
.
...
...
@@ -440,19 +448,18 @@ Notation "[[ x ]]" := (Found _ x _).
(
**
Now
our
next
version
of
[
pred
]
is
trivial
to
write
.
*
)
Definition
pred_strong
6
(
n
:
nat
)
:
{{
m
|
n
=
S
m
}}.
Definition
pred_strong
7
(
n
:
nat
)
:
{{
m
|
n
=
S
m
}}.
refine
(
fun
n
=>
match
n
return
{{
m
|
n
=
S
m
}}
with
match
n
with
|
O
=>
??
|
S
n
'
=>
[[
n
'
]]
end
)
;
trivial
.
Defined
.
(
**
Because
we
used
[
maybe
]
,
one
valid
implementation
of
the
type
we
gave
[
pred_strong
6
]
would
return
[
??
]
in
every
case
.
We
can
strengthen
the
type
to
rule
out
such
vacuous
implementations
,
and
the
type
family
[
sumor
]
from
the
standard
library
provides
the
easiest
starting
point
.
For
type
[
A
]
and
proposition
[
B
]
,
[
A
+
{
B
}
]
desugars
to
[
sumor
A
B
]
,
whose
values
are
either
values
of
[
A
]
or
proofs
of
[
B
]
.
*
)
(
**
Because
we
used
[
maybe
]
,
one
valid
implementation
of
the
type
we
gave
[
pred_strong
7
]
would
return
[
??
]
in
every
case
.
We
can
strengthen
the
type
to
rule
out
such
vacuous
implementations
,
and
the
type
family
[
sumor
]
from
the
standard
library
provides
the
easiest
starting
point
.
For
type
[
A
]
and
proposition
[
B
]
,
[
A
+
{
B
}
]
desugars
to
[
sumor
A
B
]
,
whose
values
are
either
values
of
[
A
]
or
proofs
of
[
B
]
.
*
)
Print
sumor
.
(
**
[[
(
**
%
\
vspace
{-
.15
in
}%
[[
Inductive
sumor
(
A
:
Type
)
(
B
:
Prop
)
:
Type
:=
inleft
:
A
->
A
+
{
B
}
|
inright
:
B
->
A
+
{
B
}
For
inleft
:
Argument
A
is
implicit
...
...
@@ -466,9 +473,9 @@ Notation "[[[ x ]]]" := (inleft _ [x]).
(
**
Now
we
are
ready
to
give
the
final
version
of
possibly
-
failing
predecessor
.
The
[
sumor
]
-
based
type
that
we
use
is
maximally
expressive
;
any
implementation
of
the
type
has
the
same
input
-
output
behavior
.
*
)
Definition
pred_strong
7
(
n
:
nat
)
:
{
m
:
nat
|
n
=
S
m
}
+
{
n
=
0
}.
Definition
pred_strong
8
(
n
:
nat
)
:
{
m
:
nat
|
n
=
S
m
}
+
{
n
=
0
}.
refine
(
fun
n
=>
match
n
return
{
m
:
nat
|
n
=
S
m
}
+
{
n
=
0
}
with
match
n
with
|
O
=>
!!
|
S
n
'
=>
[[[
n
'
]]]
end
)
;
trivial
.
...
...
@@ -491,8 +498,8 @@ Notation "x <- e1 ; e2" := (match e1 with
Definition
doublePred
(
n1
n2
:
nat
)
:
{{
p
|
n1
=
S
(
fst
p
)
/
\
n2
=
S
(
snd
p
)
}}.
refine
(
fun
n1
n2
=>
m1
<-
pred_strong
6
n1
;
m2
<-
pred_strong
6
n2
;
m1
<-
pred_strong
7
n1
;
m2
<-
pred_strong
7
n2
;
[[(
m1
,
m2
)]])
;
tauto
.
Defined
.
...
...
@@ -508,11 +515,12 @@ Notation "x <-- e1 ; e2" := (match e1 with
(
**
printing
*
$
\
times
$
*
)
Definition
doublePred
'
(
n1
n2
:
nat
)
:
{
p
:
nat
*
nat
|
n1
=
S
(
fst
p
)
/
\
n2
=
S
(
snd
p
)
}
Definition
doublePred
'
(
n1
n2
:
nat
)
:
{
p
:
nat
*
nat
|
n1
=
S
(
fst
p
)
/
\
n2
=
S
(
snd
p
)
}
+
{
n1
=
0
\
/
n2
=
0
}.
refine
(
fun
n1
n2
=>
m1
<--
pred_strong
7
n1
;
m2
<--
pred_strong
7
n2
;
m1
<--
pred_strong
8
n1
;
m2
<--
pred_strong
8
n2
;
[[[(
m1
,
m2
)]]])
;
tauto
.
Defined
.
...
...
@@ -552,7 +560,7 @@ Definition eq_type_dec : forall t1 t2 : type, {t1 = t2} + {t1 <> t2}.
decide
equality
.
Defined
.
(
**
Another
notation
complements
the
monadic
notation
for
[
maybe
]
that
we
defined
earlier
.
Sometimes
we
want
to
be
to
include
"assertions"
in
our
procedures
.
That
is
,
we
want
to
run
a
decision
procedure
and
fail
if
it
fails
;
otherwise
,
we
want
to
continue
,
with
the
proof
that
it
produced
made
available
to
us
.
This
infix
notation
captures
that
,
for
a
procedure
that
returns
an
arbitrary
two
-
constructor
type
.
*
)
(
**
Another
notation
complements
the
monadic
notation
for
[
maybe
]
that
we
defined
earlier
.
Sometimes
we
want
to
include
"assertions"
in
our
procedures
.
That
is
,
we
want
to
run
a
decision
procedure
and
fail
if
it
fails
;
otherwise
,
we
want
to
continue
,
with
the
proof
that
it
produced
made
available
to
us
.
This
infix
notation
captures
that
idea
,
for
a
procedure
that
returns
an
arbitrary
two
-
constructor
type
.
*
)
Notation
"e1 ;; e2"
:=
(
if
e1
then
e2
else
??
)
(
right
associativity
,
at
level
60
)
.
...
...
@@ -565,7 +573,7 @@ Definition typeCheck (e : exp) : {{t | hasType e t}}.
Hint
Constructors
hasType
.
refine
(
fix
F
(
e
:
exp
)
:
{{
t
|
hasType
e
t
}}
:=
match
e
return
{{
t
|
hasType
e
t
}}
with
match
e
with
|
Nat
_
=>
[[
TNat
]]
|
Plus
e1
e2
=>
t1
<-
F
e1
;
...
...
@@ -587,22 +595,19 @@ Defined.
(
**
Despite
manipulating
proofs
,
our
type
checker
is
easy
to
run
.
*
)
Eval
simpl
in
typeCheck
(
Nat
0
)
.
(
**
[[
(
**
%
\
vspace
{-
.15
in
}%
[[
=
[[
TNat
]]
:
{{
t
|
hasType
(
Nat
0
)
t
}}
]]
*
)
Eval
simpl
in
typeCheck
(
Plus
(
Nat
1
)
(
Nat
2
))
.
(
**
[[
(
**
%
\
vspace
{-
.15
in
}%
[[
=
[[
TNat
]]
:
{{
t
|
hasType
(
Plus
(
Nat
1
)
(
Nat
2
))
t
}}
]]
*
)
Eval
simpl
in
typeCheck
(
Plus
(
Nat
1
)
(
Bool
false
))
.
(
**
[[
(
**
%
\
vspace
{-
.15
in
}%
[[
=
??
:
{{
t
|
hasType
(
Plus
(
Nat
1
)
(
Bool
false
))
t
}}
]]
*
)
...
...
@@ -700,7 +705,7 @@ Qed.
(
**
Now
we
can
define
the
type
-
checker
.
Its
type
expresses
that
it
only
fails
on
untypable
expressions
.
*
)
(
*
end
thide
*
)
Definition
typeCheck
'
(
e
:
exp
)
:
{
t
:
type
|
hasType
e
t
}
+
{
forall
t
,
~
hasType
e
t
}.
Definition
typeCheck
'
(
e
:
exp
)
:
{
t
:
type
|
hasType
e
t
}
+
{
forall
t
,
~
hasType
e
t
}.
(
*
begin
thide
*
)
Hint
Constructors
hasType
.
(
**
We
register
all
of
the
typing
rules
as
hints
.
*
)
...
...
@@ -709,8 +714,9 @@ Definition typeCheck' (e : exp) : {t : type | hasType e t} + {forall t, ~hasType
(
**
[
hasType_det
]
will
also
be
useful
for
proving
proof
obligations
with
contradictory
contexts
.
Since
its
statement
includes
[
forall
]
-
bound
variables
that
do
not
appear
in
its
conclusion
,
only
[
eauto
]
will
apply
this
hint
.
*
)
(
**
Finally
,
the
implementation
of
[
typeCheck
]
can
be
transcribed
literally
,
simply
switching
notations
as
needed
.
*
)
refine
(
fix
F
(
e
:
exp
)
:
{
t
:
type
|
hasType
e
t
}
+
{
forall
t
,
~
hasType
e
t
}
:=
match
e
return
{
t
:
type
|
hasType
e
t
}
+
{
forall
t
,
~
hasType
e
t
}
with
refine
(
fix
F
(
e
:
exp
)
:
{
t
:
type
|
hasType
e
t
}
+
{
forall
t
,
~
hasType
e
t
}
:=
match
e
with
|
Nat
_
=>
[[[
TNat
]]]
|
Plus
e1
e2
=>
t1
<--
F
e1
;
...
...
@@ -729,6 +735,8 @@ Definition typeCheck' (e : exp) : {t : type | hasType e t} + {forall t, ~hasType
(
**
We
clear
[
F
]
,
the
local
name
for
the
recursive
function
,
to
avoid
strange
proofs
that
refer
to
recursive
calls
that
we
never
make
.
The
[
crush
]
variant
[
crush
'
]
helps
us
by
performing
automatic
inversion
on
instances
of
the
predicates
specified
in
its
second
argument
.
Once
we
throw
in
[
eauto
]
to
apply
[
hasType_det
]
for
us
,
we
have
discharged
all
the
subgoals
.
*
)
(
*
end
thide
*
)
Defined
.
(
**
The
short
implementation
here
hides
just
how
time
-
saving
automation
is
.
Every
use
of
one
of
the
notations
adds
a
proof
obligation
,
giving
us
12
in
total
.
Most
of
these
obligations
require
multiple
inversions
and
either
uses
of
[
hasType_det
]
or
applications
of
[
hasType
]
rules
.
...
...
@@ -736,24 +744,21 @@ Defined.
The
results
of
simplifying
calls
to
[
typeCheck
'
]
look
deceptively
similar
to
the
results
for
[
typeCheck
]
,
but
now
the
types
of
the
results
provide
more
information
.
*
)
Eval
simpl
in
typeCheck
'
(
Nat
0
)
.
(
**
[[
(
**
%
\
vspace
{-
.15
in
}%
[[
=
[[[
TNat
]]]
:
{
t
:
type
|
hasType
(
Nat
0
)
t
}
+
{
(
forall
t
:
type
,
~
hasType
(
Nat
0
)
t
)
}
]]
*
)
Eval
simpl
in
typeCheck
'
(
Plus
(
Nat
1
)
(
Nat
2
))
.
(
**
[[
(
**
%
\
vspace
{-
.15
in
}%
[[
=
[[[
TNat
]]]
:
{
t
:
type
|
hasType
(
Plus
(
Nat
1
)
(
Nat
2
))
t
}
+
{
(
forall
t
:
type
,
~
hasType
(
Plus
(
Nat
1
)
(
Nat
2
))
t
)
}
]]
*
)
Eval
simpl
in
typeCheck
'
(
Plus
(
Nat
1
)
(
Bool
false
))
.
(
**
[[
(
**
%
\
vspace
{-
.15
in
}%
[[
=
!!
:
{
t
:
type
|
hasType
(
Plus
(
Nat
1
)
(
Bool
false
))
t
}
+
{
(
forall
t
:
type
,
~
hasType
(
Plus
(
Nat
1
)
(
Bool
false
))
t
)
}
...
...
@@ -772,11 +777,11 @@ Eval simpl in typeCheck' (Plus (Nat 1) (Bool false)).
%
\
item
%
#
<
li
>
#
Define
an
inductive
type
[
prop
]
of
propositional
logic
formulas
,
consisting
of
variables
,
negation
,
and
binary
conjunction
and
disjunction
.
#
</
li
>
#
%
\
item
%
#
<
li
>
#
Define
a
function
[
propDenote
]
from
variable
truth
assignments
and
[
prop
]
s
to
[
Prop
]
,
based
on
the
usual
meanings
of
the
connectives
.
Represent
truth
assignments
as
functions
from
[
var
]
to
[
bool
]
.
#
</
li
>
#
%
\
item
%
#
<
li
>
#
Define
a
function
[
bool_true_dec
]
that
checks
whether
a
boolean
is
true
,
with
a
maximally
expressive
dependent
type
.
That
is
,
the
function
should
have
type
[
forall
b
,
{
b
=
true
}
+
{
b
=
true
->
False
}
]
.
#
</
li
>
#
%
\
item
%
#
<
li
>
#
Define
a
function
[
decide
]
that
determines
whether
a
particular
[
prop
]
is
true
under
a
particular
truth
assignment
.
That
is
,
the
function
should
have
type
[
forall
(
truth
:
var
->
bool
)
(
p
:
prop
)
,
{
propDenote
truth
p
}
+
{
~
propDenote
truth
p
}
]
.
This
function
is
probably
easiest
to
write
in
the
usual
tactical
style
,
instead
of
programming
with
[
refine
]
.
[
bool_true_dec
]
may
come
in
handy
as
a
hint
.
#
</
li
>
#
%
\
item
%
#
<
li
>
#
Define
a
function
[
negate
]
that
returns
a
simplified
version
of
the
negation
of
a
[
prop
]
.
That
is
,
the
function
should
have
type
[
forall
p
:
prop
,
{
p
'
:
prop
|
forall
truth
,
propDenote
truth
p
<->
~
propDenote
truth
p
'
}
]
.
To
simplify
a
variable
,
just
negate
it
.
Simplify
a
negation
by
returning
its
argument
.
Simplify
conjunctions
and
disjunctions
using
De
Morgan
'
s
laws
,
negating
the
arguments
recursively
and
switching
the
kind
of
connective
.
[
decide
]
may
be
useful
in
some
of
the
proof
obligations
,
even
if
you
do
not
use
it
in
the
computational
part
of
[
negate
]
'
s
definition
.
Lemmas
like
[
decide
]
allow
us
to
compensate
for
the
lack
of
a
general
Law
of
the
Excluded
Middle
in
CIC
.
#
</
li
>
#
%
\
item
%
#
<
li
>
#
Define
a
function
[
decide
]
that
determines
whether
a
particular
[
prop
]
is
true
under
a
particular
truth
assignment
.
That
is
,
the
function
should
have
type
[
forall
(
truth
:
var
->
bool
)
(
p
:
prop
)
,
{
propDenote
truth
p
}
+
{
~
propDenote
truth
p
}
]
.
This
function
is
probably
easiest
to
write
in
the
usual
tactical
style
,
instead
of
programming
with
[
refine
]
.
[
bool_true_dec
]
may
come
in
handy
as
a
hint
.
#
</
li
>
#
%
\
item
%
#
<
li
>
#
Define
a
function
[
negate
]
that
returns
a
simplified
version
of
the
negation
of
a
[
prop
]
.
That
is
,
the
function
should
have
type
[
forall
p
:
prop
,
{
p
'
:
prop
|
forall
truth
,
propDenote
truth
p
<->
~
propDenote
truth
p
'
}
]
.
To
simplify
a
variable
,
just
negate
it
.
Simplify
a
negation
by
returning
its
argument
.
Simplify
conjunctions
and
disjunctions
using
De
Morgan
'
s
laws
,
negating
the
arguments
recursively
and
switching
the
kind
of
connective
.
[
decide
]
may
be
useful
in
some
of
the
proof
obligations
,
even
if
you
do
not
use
it
in
the
computational
part
of
[
negate
]
'
s
definition
.
Lemmas
like
[
decide
]
allow
us
to
compensate
for
the
lack
of
a
general
Law
of
the
Excluded
Middle
in
CIC
.
#
</
li
>
#
#
</
ol
>
#
%
\
end
{
enumerate
}%
#
</
li
>
#
%
\
item
%
#
<
li
>
#
Implement
the
DPLL
satisfiability
decision
procedure
for
boolean
formulas
in
conjunctive
normal
form
,
with
a
dependent
type
that
guarantees
its
correctness
.
An
example
of
a
reasonable
type
for
this
function
would
be
[
forall
f
:
formula
,
{
truth
:
tvals
|
formulaTrue
truth
f
}
+
{
forall
truth
,
~
formulaTrue
truth
f
}
]
.
Implement
at
least
"the basic backtracking algorithm"
as
defined
here
:
%
\
item
%
#
<
li
>
#
Implement
the
DPLL
satisfiability
decision
procedure
for
boolean
formulas
in
conjunctive
normal
form
,
with
a
dependent
type
that
guarantees
its
correctness
.
An
example
of
a
reasonable
type
for
this
function
would
be
[
forall
f
:
formula
,
{
truth
:
tvals
|
formulaTrue
truth
f
}
+
{
forall
truth
,
~
formulaTrue
truth
f
}
]
.
Implement
at
least
"the basic backtracking algorithm"
as
defined
here
:
%
\
begin
{
center
}
\
url
{
http
:
//en.wikipedia.org/wiki/DPLL_algorithm}\end{center}%
#
<
blockquote
><
a
href
=
"http://en.wikipedia.org/wiki/DPLL_algorithm"
>
http
:
//en.wikipedia.org/wiki/DPLL_algorithm</a></blockquote>#
It
might
also
be
instructive
to
implement
the
unit
propagation
and
pure
literal
elimination
optimizations
described
there
or
some
other
optimizations
that
have
been
used
in
modern
SAT
solvers
.
#
</
li
>
#
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment