Итак, во-первых, это нормально для вас, чтобы быть смущенным этим, но это может быть проще, чем вы думаете!
Есть два различных понятия, которые вы запутали, поэтому давайте рассмотрим их по одномувремя.Во-первых, вы упоминаете, что ev 0
- это предложение, и удивляетесь, что делает его правдивым.В какой-то момент вы узнаете, что суждения и типы - это одно и то же, и различие между Prop
и Set
и Type
не в том, что эти вещи по своей сути различны.
Итак, когда вы определяететип (или предложение) nat
, вы создаете новый тип и описываете, какие значения существуют в нем.Вы заявляете, что существует значение O
, то есть nat
.И вы объявляете, что есть параметризованное значение S
, то есть nat
, когда передано nat
.
Таким же образом, когда вы определяете тип (или предложение) ev
вы создаете новый тип (ну, на самом деле это семейство типов, индексируемых значениями типа nat
) и описываете, какие значения существуют в этих ev
типах.Вы заявляете, что существует значение ev_0
, то есть ev 0
.И вы заявляете, что есть параметризованное значение ev_SS
, то есть ev (S (S n))
, когда передано n : nat
и ev n
.
Итак, вы сделали предложениеправда, имея способы создания ценностей внутри него.Вы также можете определить ложное предложение, не имея конструкторов или имея конструкторы, которые никогда не могут быть вызваны:
Inductive MyFalse1 := . (* no constructor! *)
Inductive MyFalse2 :=
| TryToConstructMe : False -> MyFalse2
| ThisWontWorkEither : 0 = 1 -> MyFalse2
.
Я объявил два типа теперь (или предложение), но нет способа засвидетельствовать их, потому что онилибо не имеют конструкторов, либо не имеют возможности когда-либо вызывать эти конструкторы.
Что касается именования вещей, ev_0
, ev_SS
, O
и S
все одинаковывид объекта: конструктор.Я не уверен, почему вы думаете, что ev_0
является указателем на значение ev 0
.
Нет смысла присваивать ev n
в качестве предложения, кроме того, что это предложение может бытьЗначение true, если существует способ для создания значения с типом ev n
, и может быть ложным, если нет способа создать значение с типом ev n
.
Однако обратите внимание, что ev n
былтщательно продуманный, чтобы быть обитаемым ровно для тех n
с, которые являются четными, и необитаемыми именно для тех n
с, которые являются нечетными.В этом смысле ev
фиксирует предложение.Если вы получаете значение типа ev n
, оно по существу утверждает, что n
является четным числом, поскольку тип ev n
содержит жителей только для четных значений:
ev 0
содержит 1житель (ev_0
) ev 1
содержит 0 жителей ev 2
содержит 1 жителя (ev_SS 0 ev_0
) ev 3
содержит 0 жителей ev 4
содержит 1 жителя (ev_SS 2 (ev_SS 0 ev_0)
) - и т. Д.
Наконец, для разницы между Set
, Prop
и Type
, это все вселенные, в которых вы можете создавать индуктивные типы, но они имеют определенные ограничения.
Prop
позволяет оптимизировать генерацию кода.Для вас, программиста, это по сути способ пометить некоторый тип как используемый только для целей проверки, никогда не используемый для целей вычислений.В результате проверка типов заставит вас никогда не вычислять доказательства в пределах вселенной Prop
, и генерация кода будет знать, что она может отбросить эти доказательства, поскольку они не участвуют в вычислительном поведении.
Set
- это просто ограничение Prop
во избежание обращения с уровнями вселенной.На самом деле вам не нужно понимать это до тех пор, пока вы не станете учиться позже.
Вы действительно должны стараться не думать о Prop
как о волшебной вещи, отличной от Set
.
Вам может помочь следующее: мы могли бы переписать определения nat
и ev
, полностью эквивалентным образом, как:
Inductive nat1 : Set :=
| O : nat1
| S : nat1 -> nat1
.
(* is the same as *)
Inductive nat1 : Set :=
| O : nat1
| S : forall (n : nat1), nat1
.
(* and *)
Inductive ev : nat -> Prop :=
| ev_0 : ev 0
| ev_SS : forall (n : nat), ev n -> ev (S (S n))
.
(* is the same as *)
Inductive ev : nat -> Prop :=
| ev_0 : ev 0
| ev_SS : forall (n : nat) (e : ev n), ev (S (S n))
.
Каждый раз, когда вы видите тип, похожий на a -> b
, это действительно сокращение для forall (_ : a), b
, то есть мы ожидаем ввод типа a
и возвращаем вывод типа b
.
Причина, по которой мы пишем forall (n : nat)
в ev_SS
, заключается в том, что у нас есть для присвоения имени первому аргументу, поскольку тип второго аргумента будет зависеть от него (второй аргумент имеетвведите ev n
).