Agda-подобное программирование в Coq / Proof General?

В отличие от Agda, Coq имеет тенденцию отделять доказательства от функций. Тактика Coq отлично подходит для написания доказательств, но мне интересно, есть ли способ воспроизвести некоторые функции Agda-режима.

в частности, я хотел бы:

  • некоторый эквивалент Agda ? или Хаскелл _, где я могу опустить часть функции, пока я ее пишу, и (надеюсь) Coq скажет мне тип, который мне нужно поместить туда
  • эквивалент C-c C - r в Agda режим (reify), где вы заполняете ? блок с функцией, и он сделает новый ? блоки нужных аргументов
  • когда я делаю match в функции, имея Coq автоматически писать развернуть возможные ветви (например, C-c C-a в Agda-режиме)

возможно ли это в Coqide или Proof General?

2 ответов


как было предложено ejgallego в комментариях, вы можете (почти) сделать это. Есть компания-coq инструмент, который работает поверх ProofGeneral.

позвольте мне продемонстрировать, как map функция может быть реализована с помощью company-coq и refine тактика. Начать с

Fixpoint map {A B} (f : A -> B) (xs : list A) : list B.

тип refine ()., затем поместите курсор внутри скобок и типа С-С С-РЕТ РЕТ список -- он вставляет match выражение на списках с отверстиями вы заполните вручную (давайте заполним имя списка и базовый регистр).

Fixpoint map {A B} (f : A -> B) (xs : list A) : list B.
  refine (match xs with
          | nil => nil
          | cons x x0 => cons _ _
          end).

чтобы закончить его, мы переименовываем x0 на tl и обеспечить рекурсивный случай exact (map A B f tl).:

Fixpoint map {A B} (f : A -> B) (xs : list A) : list B.
  refine (match xs with
          | nil => nil
          | cons x tl => cons _ _
          end).
  exact (f x).
  exact (map A B f tl).
Defined.

существует также полезная комбинация клавиш C-c C-a C-x что помогает извлечь текущую цель в отдельную лемму/вспомогательную функцию.


позвольте мне научить вас одному странному трюку. Это может быть не ответ на все ваши проблемы, но это может помочь, по крайней мере концептуально.

давайте реализуем сложение для натуральных чисел, последнее задается

Inductive nat : Set :=
  | zero : nat
  | suc : nat -> nat.

можно попробовать написать дополнение по тактике, но это происходит.

Theorem plus' : nat -> nat -> nat.
Proof.
  induction 1.

plus' < 2 subgoals

  ============================
   nat -> nat

subgoal 2 is:
 nat -> nat

вы не можете видеть, что вы делаете.

фокус в том, чтобы более внимательно посмотреть на то, что вы делаете. Мы можем ввести безвозмездно зависимый тип, клонирование nat.

Inductive PLUS (x y : nat) : Set :=
  | defPLUS : nat -> PLUS x y.

идея в том, что PLUS x y - это тип " способ вычисления plus x y". Нам понадобится проекция, позволяющая извлечь результат такого вычисления.

Theorem usePLUS : forall x y, PLUS x y -> nat.
Proof.
  induction 1.
    exact n.
Defined.

теперь мы готовы программировать, доказывая.

Theorem mkPLUS : forall x y, PLUS x y.
Proof.

mkPLUS < 1 subgoal

  ============================
   forall x y : nat, PLUS x y

заключение цели показывает нам нашу текущую левую сторону и контекст. Аналог C-c C-c в Agda есть...

  induction x.

mkPLUS < 2 subgoals

  ============================
   forall y : nat, PLUS zero y

subgoal 2 is:
 forall y : nat, PLUS (suc x) y

и вы можете видеть, что он сделал разделение дела! Давайте отбросьте базовый корпус.

    intros y.
      exact (defPLUS zero y    y).

вызов конструктора PLUS похож на написание уравнения. Представьте себе = знак перед третьим аргументом. Для случая step нам нужно сделать рекурсивный вызов.

    intros y.
      eapply (fun h => (defPLUS (suc x) y    (suc (usePLUS x y h)))).

сделать рекурсивный вызов, мы вызываем usePLUS с аргументами, которые мы хотим, здесь x и y, но мы абстрагируемся от третьего аргумента, который является объяснением того, как на самом деле его вычислить. У нас осталась только эта подцель., эффективно проверка прекращения.

mkPLUS < 1 subgoal

  x : nat
  IHx : forall y : nat, PLUS x y
  y : nat
  ============================
   PLUS x y

и теперь, вместо того, чтобы использовать проверку защищенности Coq, вы используете...

        auto.

...который проверяет, что индуктивные гипотезы охватывают рекурсивный вызов. Мы

Defined.

у нас есть рабочий, но нам нужна обертка.

Theorem plus : nat -> nat -> nat.
Proof.
  intros x y.
    exact (usePLUS x y (mkPLUS x y)).
Defined.

и мы готовы пойти.

Eval compute in (plus (suc (suc zero)) (suc (suc zero))).

Coq <      = suc (suc (suc (suc zero)))
     : nat

вы есть интерактивный строительный инструмент. Вы can игра, чтобы показать вам соответствующие детали проблемы, которую вы решаете, делая типы более информативными. Полученный сценарий доказательства...

Theorem mkPLUS : forall x y, PLUS x y.
Proof.
  induction x.
    intros y.
      exact             (defPLUS zero    y    y).
    intros y.
      eapply (fun h =>  (defPLUS (suc x) y    (suc (usePLUS x y h)))).
        auto.
Defined.

... является явным о программе, которую он создает. Вы можете видеть, что это определяющее дополнение.

если вы автоматизируете эту настройку для построения программы, то слой на интерфейсе, показывающий вам программу, которую вы строите, и ключевую проблему-упрощение тактики, вы получите забавный маленький язык программирования под названием Epigram 1.