При проверке типов Coq использует более слабую форму равенства (иногда называемую равенством определений, суждений или вычислений).В отличие от пропозиционального равенства (с которым «=» связывается по умолчанию), дефиниционное равенство разрешимо.Coq может взять любые два условия и решить, можно ли преобразовать одно в другое.Если бы при проверке типов было разрешено пропозициональное равенство, проверка типов больше не была бы решаема 1 .
Чтобы решить вашу проблему (и это довольно большая проблема), у вас есть несколько вариантов.
Сделать Struct
запись
Я продемонстрирую принцип, используя списки.Во-первых, у нас есть понятие нестандартных списков.
Inductive UnsizedList (A: Type) :=
| unil
| ucons (a: A) (u: UnsizedList A).
Arguments unil [A], A.
Arguments ucons [A] a u, A a u.
Fixpoint length {A: Type} (u: UnsizedList A) :=
match u with
| unil => 0
| ucons _ u' => S (length u')
end.
Мы также можем определить размерный список, где каждый элемент SizedList A n
имеет длину n
.
Inductive SizedList (A: Type): nat -> Type :=
| snil: SizedList A 0
| scons {n: nat} (a: A) (u: SizedList A n): SizedList A (S n).
ЭтоОпределение сталкивается с той же проблемой, что и ваша.Например, если вы хотите показать, что конкатенация ассоциативна, вы не можете просто доказать concat (concat u v) w = concat u (concat v w)
, так как две стороны равенства имеют разные типы ((i + j) + k
против i + (j + k)
).Если бы мы могли просто сказать Coq, какого размера мы ожидаем, что список будет, а затем доказать это позже, мы могли бы решить это.Это то, что делает это определение, которое объединяет UnsizedList
с доказательством того, что этот список имеет желаемую длину.
Record SizedListPr (A: Type) (n: nat): Type := {
list: UnsizedList A;
list_len_eq: length list = n;
}.
Теперь мы можем иметь concat (concat u v) w = concat u (concat v w)
;нам просто нужно доказать, что обе стороны имеют длину (i + j) + k
.
Использовать принуждения
Этот подход может стать довольно грязным, если вы не будете осторожны, так что это не часто предпочтительный подход.
Позвольте мне определить вид принуждения, который отображает элементы типа P x
на элементы типа P y
, если x = y
. 2
Definition coercion {A: Type} (P: A -> Type) {x y: A} (p: x = y): P x -> P y :=
match p with
| eq_refl => fun t => t
end.
Здесь мыиспользуйте индукцию на срок p: x = y
.Принцип индукции говорит, по сути, что если мы можем что-то доказать, когда x
и y
определенно равны, то мы можем доказать это, когда они пропозиционально равны. 3 Когда P x
и P y
одинаковы, мы можем просто использовать функцию тождества.
Теперь, например, оператор ассоциативности конкатенации для списков с размерами равен concat (concat u v) w = coercion (SizedList A) (add_assoc) (concat u (concat v w))
.Таким образом, мы приводим что-то типа SizedList A (i + (j + k))
к чему-то типа SizedList A ((i + j) + k)
, используя равенство add_assoc: i + (j + k) = (i + j) + k
(я упустил некоторые параметры для удобочитаемости).
Какой выбор вы делаете, довы.Обсуждение этой проблемы и связанных с ней проблем, а также некоторые дополнительные решения можно найти в Сертифицированном программировании с зависимыми типами страница Равенство .
1 См. теория экстенсиональных типов для класса теорий, где это обычно происходит. Тезис Мартина Хофманна содержит обзор различий между интенциональными и экстенсиональными теориями.
2 Если вы знакомы с теорией гомотопических типов, это transport
.
3 В этом утверждении достаточно предостережений, что различия между пропозициональным и дефиниционным равенством все еще существуют.