Сохранение информации при использовании индукции?

Я использую Coq Proof Assistant для реализации модели (небольшого) языка программирования (расширение реализации Featherweight Java Бруно Де Фрайне, Эриком Эрнстом, Марио Зюдхолтом). Одна вещь, которая постоянно возникает при использовании тактики induction, - это как сохранить информацию, заключенную в конструкторы типов.

У меня есть подпрограмма Prop, реализованная как

Inductive sub_type : typ -> typ -> Prop :=
| st_refl : forall t, sub_type t t
| st_trans : forall t1 t2 t3, sub_type t1 t2 -> sub_type t2 t3 -> sub_type t1 t3
| st_extends : forall C D,
    extends C D ->
    sub_type (c_typ C) (c_typ D).

Hint Constructors sub_type.

где extends - это механизм расширения класса, как замечено в Java, а typ представляет два различных типа доступных типов,

Inductive typ : Set :=
| c_typ : cname -> typ
| r_typ : rname -> typ.

Примером того, где я хотел бы сохранить информацию о типе, является использование тактики induction для гипотезы вроде

H: sub_type (c_typ u) (c_typ v)

E.g. in

u : cname
v : cname
fsv : flds
H : sub_type (c_typ u) (c_typ v)
H0 : fields v fsv
============================
 exists fs : flds, fields u (fsv ++ fs)

использование induction H. отбрасывает всю информацию о u и v. Случай st_refl становится

u : cname
v : cname
fsv : flds
t : typ
H0 : fields v fsv
============================
 exists fs : flds, fields u (fsv ++ fs)

Как видите, информация о том, что u и v относятся к typ конструкторам в H и, следовательно, к t, потеряна. Что еще хуже, из-за этого Coq не может видеть, что u и v фактически должны быть одинаковыми в этом случае.

При использовании тактики inversion на H Coq удается увидеть, что u и v одинаковы. Однако эта тактика здесь неприменима, так как мне нужны индукционные гипотезы, которые induction генерируют, чтобы доказать случаи st_trans и st_extends.

Есть ли тактика, которая сочетает в себе лучшее из inversion и induction, чтобы генерировать гипотезы индукции и вывести равенства, не разрушая информацию о том, что содержится в конструкторах? В качестве альтернативы, есть ли способ вручную получить нужную мне информацию? info inversion H и info induction H показывают, что многие преобразования применяются автоматически (особенно с inversion). Это заставило меня экспериментировать с тактикой change вместе с let ... in построением, но без какого-либо прогресса.


coq
person mdiin    schedule 23.12.2010    source источник


Ответы (3)


Это общая проблема, когда вам нужно провести индукцию по гипотезе с зависимым типом (sub_type (c_typ u) (c_typ v)), параметры которого имеют определенную структуру (c_typ u). Существует общий трюк, который состоит в том, чтобы выборочно переписать структурированный параметр в переменную, сохраняя равенство в среде.

set (t1 := c_typ u) in H; assert (Eq1 : t1 = c_typ u) by reflexivity; clearbody t1.
set (t2 := c_typ u) in H; assert (Eq2 : t2 = c_typ u) by reflexivity; clearbody t2.
induction H. (*often "; try subst" or "; try rewrite Eq1; try rewrite Eq2" *).

Начиная с Coq 8.2, этот общий шаблон set-assert-clearbody выполняется с помощью встроенной тактики remember term as ident in *goal_occurences*.

Вот глупая лемма, доказанная с помощью этой тактики.

Lemma subtype_r_left_equal :
  forall r1 t2, sub_type (r_typ r1) t2 -> r_typ r1 = t2.
Proof.
  intros.
  remember (r_typ r1) as t1 in H.
  induction H.
  congruence.
  solve [firstorder].
  discriminate.
Qed.

Бонусный совет (по опыту, но это было давно, поэтому я не помню подробностей): когда вы делаете достаточно синтаксические рассуждения о системах типов (что обычно имеет место, когда вы делаете такого рода механические доказательства), это может быть удобно продолжать вводить суждения в Set. Думайте о вводе производных как об объектах, о которых вы думаете. Я помню случаи, когда было удобно вводить равенства при вводе выводов, что не всегда работает с вводом выводов в Prop.


Вот вам доказательство рефлексивности с вашим Problem.v. Что касается транзитивности, я подозреваю, что ваша гипотеза индукции недостаточно сильна. Это может быть побочным продуктом того, как вы упростили задачу, хотя транзитивность часто требует неожиданно сложных индукционных гипотез или лемм.

Fact sub_type_fields: forall u v fsv,
  sub_type (c_typ u) (c_typ v) -> fields v fsv ->
  exists fs, fields u (fsv ++ fs).
Proof.
  intros.
  remember (c_typ u) as t1 in H.
  remember (c_typ v) as t2 in H.
  induction H.
  (* case st_refl *)
  assert (v = u). congruence. subst v t.
  exists nil. rewrite <- app_nil_end. assumption.
  (* case st_trans *)
  subst t1 t3.
  (* case st_extends *)
Admitted.
person Gilles 'SO- stop being evil'    schedule 23.12.2010
comment
@Matthias: generalize dependent H0. induction H. помогает? Это все, что я могу предложить, не имея того, что я мог бы скормить Coq сам (в вашем вопросе отсутствует больше определений, чем я хотел бы заполнить, я недостаточно знаком с системой типов Java). - person Gilles 'SO- stop being evil'; 24.12.2010
comment
Это не убедило Coq поступить правильно. Я создал zip-файл, содержащий только определения, необходимые для игры с Fact. У меня возникли проблемы с доказательством: Problem.v содержит определения и Fact, остальные являются вспомогательными. Я ценю вашу помощь. - person mdiin; 24.12.2010
comment
@Matthias: Для рефлексивности вам просто нужно переписать цель, используя доступные равенства. Я считаю, что для одноразового использования проще всего утверждать равенство, а затем использовать его. Если это появится во множестве доказательств, вы можете начать определять тактику, которая ищет общие закономерности. - person Gilles 'SO- stop being evil'; 24.12.2010
comment
тактика запоминания и возврата, возможно, даже проще в использовании. - person Vinz; 17.01.2011

Я столкнулся с аналогичной проблемой, и тактика «зависимой индукции» Coq 8.3 позаботилась о бизнесе.

person Adriaan Moors    schedule 04.02.2011
comment
В моем случае это было фактически потому, что доказательство было невозможно из-за проблемы в семантических правилах, которые я определил. Когда проблема была решена, доказательство было относительно простым. :-) И в целом я обнаружил, что неплохо было бы сделать шаг назад и проверить определения, которые я использую, если что-то слишком сложно доказать. - person mdiin; 05.02.2011
comment
это когда-нибудь что-то значит, если вам нужно и то, и другое? Например, если ваша индукция терпит неудачу, это часто происходит из-за того, что ваша гипотеза индукции слишком слаба. - person sam boosalis; 07.03.2013

Я был уверен, что у CPDT есть какие-то комментарии по этому поводу, но не совсем очевидно, где именно. Вот несколько ссылок:

  1. http://adam.chlipala.net/cpdt/html/Cpdt.Predicates.html В разделе «Предикаты с неявным равенством» показан, пожалуй, самый простой случай, когда Coq «теряет информацию» (при разрушении, а не индукции). Он также объясняет, ПОЧЕМУ эта информация теряется: когда вы разрушаете тип, применяемый к аргумент, который не является свободной переменной, эти типы сначала заменяются свободными переменными (вот почему Coq теряет информацию).

  2. http://adam.chlipala.net/cpdt/html/Cpdt.Universes.html В разделе «Методы ухода от аксиом» показаны некоторые уловки, позволяющие избежать аксиомы K, в том числе «уловка равенства», описанная Жилем. Найдите «использование общего трюка, основанного на равенстве, для поддержки индукции по неизменяемым аргументам для семейств типов»

Я думаю, что это явление тесно связано с зависимым сопоставлением с образцом.

person Edward Z. Yang    schedule 01.05.2016