Jak zdefiniować funkcję indukcyjnie na podstawie dwóch argumentów w Coq?


14

Jak przekonać Coq, że podana poniżej funkcja rekurencyjna kończy się? Funkcja przyjmuje dwa argumenty indukcyjne. Intuicyjnie rekursja kończy się, ponieważ którykolwiek argument jest rozkładany.

W szczególności funkcja przyjmuje dwa drzewa jako dane wejściowe.

Inductive Tree :=
| Tip: Tree
| Bin: Tree -> Tree -> Tree.

Na drzewach lubię stosować następujący styl indukcji.

Inductive TreePair :=
| TipTip : TreePair
| TipBin : Tree -> Tree -> TreePair
| BinTip : Tree -> Tree -> TreePair
| BinBin : TreePair -> TreePair -> TreePair.

Fixpoint pair (l r: Tree): TreePair :=
  match l with
    | Tip =>
      match r with
        | Tip => TipTip
        | Bin rl rr => TipBin rl rr
      end
    | Bin ll lr =>
      match r with
        | Tip => BinTip ll lr
        | Bin rl rr => BinBin (pair l rl) (pair lr r)
      end
  end.

Definicja TreePair jest akceptowana, ale definicja pary funkcji zwraca komunikat o błędzie:

Error: Cannot guess decreasing argument of fix.

Jestem więc zainteresowany tym, jak przekonać Coq o wypowiedzeniu.


1
Czy próbowałeś razem podawać razem produkty jako produkt zamiast curry? To powinno pomóc.
Per Vognsen,

1
Niektóre osoby uważają, że to pytanie dotyczy programowania i poza zakresem tej witryny. Chociaż nie jestem pewien, czy się zgadzam, możesz chcieć wiedzieć o potencjalnym problemie. Jeśli ktoś ma coś do powiedzenia na temat stosowności, napisz o meta dyskusji, do której linkowałem.
Tsuyoshi Ito

3
To pytanie naprawdę dotyczy określenia monotonicznie malejących granic struktur danych, aby zapewnić pairprawidłowe zdefiniowanie operacji . Coq to tylko pojazd.
Dave Clarke

Odpowiedzi:


12

Definicje punktów Coq wymagają, aby wywołania indukcyjne otrzymywały strukturalnie mniejszy argument. Głęboko w konstrukcji punktu stałego bierze się jeden argument: nie ma wbudowanej koncepcji definicji rekurencyjnej na podstawie dwóch argumentów. Na szczęście definicja Coq strukturalnie mniejsza obejmuje typy wyższego rzędu, co jest niezwykle potężne.

Definicja punktu stałego z dwoma argumentami jest prosta: albo pierwszy argument staje się mniejszy, albo pierwszy argument pozostaje identyczny, a drugi argument staje się mniejszy. Ten dość powszechny wzorzec można rozwiązać za pomocą prostej poprawki.

Fixpoint pair l := fix pair1 (r : Tree) :=
  match l with
    | Tip => match r with
              | Tip => TipTip
              | Bin rl rr => TipBin rl rr
            end
    | Bin ll lr => match r with
                    | Tip => BinTip ll lr
                    | Bin rl rr => BinBin (pair1 rl) (pair lr r)
                   end
  end.

W przypadku bardziej skomplikowanych przypadków lub jeśli twoje poglądy przebiegają w ten sposób, możesz użyć rekurencji bliżej sposobu nauczania na kursach matematycznych, budując punkt stały z obliczeń kroków i osobnego uzasadnionego argumentu , często stosując miarę całkowitą . Możesz także sprawić, by twoja definicja wyglądała bardziej jak klasyczny program w języku niecałkowitym z oddzielnym zakończeniem za pomocą Programjęzyka ojczystego .


Teraz wiem, że o to prosiłem!
yhirai

czy zrobi to jakąkolwiek różnicę, jeśli popchnę fix pair1 rdo drugiej gałęzi najwyższego poziomu match(i oczywiście dostosuję pierwszą gałąź, aby odpowiednio zwrócić typ funkcji)?
dzień

@plmday: Praca w obie strony. Są one równoważne pod względem rozszerzenia dla pewnej rozsądnej definicji ekstensywności, a co ważniejsze, oba są dobrze napisane (przepisywanie ekstensywne nie zmienia żadnej z odpowiednich właściwości kowariancji (pozytywności)).
Gilles „SO- przestań być zły”
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.