중첩 된 구성 요소가있는 유도 유형에 대한 재귀 정의


21

중첩되었지만 엄격하게 긍정적 인 위치에 재귀 발생이있는 유도 유형을 고려하십시오. 예를 들어, 일반 목록 데이터 구조를 사용하여 하위를 저장하는 노드가있는 유한 분기가있는 트리입니다.

Inductive LTree : Set := Node : list LTree -> LTree.

트리와 트리 목록을 반복하여 이러한 트리에 대해 재귀 함수를 정의하는 순진한 방법은 작동하지 않습니다. 다음 size은 노드 수를 계산하는 함수를 사용한 예입니다 .

Fixpoint size (t : LTree) : nat := match t with Node l => 1 + (size_l l) end
with size_l (l : list LTree) : nat := match l with
    | nil => 0
    | cons h r => size h + size_l r
  end.

이 정의는 형식이 잘못되었습니다 (오류 메시지 발췌).

Error:
Recursive definition of size_l is ill-formed.
Recursive call to size has principal argument equal to
"h" instead of "r".

r분명히 정의 의 하위 용어인데 왜 정의가 잘못 l되었습니까? 이러한 데이터 구조에서 재귀 함수를 정의하는 방법이 있습니까?


Coq 구문에 유창하지 않은 경우 : LTree다음 문법에 해당하는 유도 유형입니다.

아르 자형이자형이자형:: =|나는에스(아르 자형이자형이자형)

우리는 size나무와 목록에 대한 유도로 함수 를 정의하려고 시도 합니다. OCaml에서는 다음과 같습니다.

type t = Node of t list
let rec size = function Node l -> 1 + size_l l
and size_l = function [] -> 0
                    | h::r -> size h + size_l r

이것이 주제입니까? 잘 모르겠습니다. Meta에 대해 논의 해 봅시다 .
Gilles 'SO- 악마 그만'

Coqy와 mathy에 동등한 함수 정의를 추가 할 수 있습니까? 구문을 이해하는 데 어려움이 있습니다.
Raphael

1
내가 시도한 @Raphael, 지금은 더 나아 졌습니까? 솔직히이 질문은 Coq에만 해당됩니다.
Gilles 'SO- 악마 중지'

답변:


14

작동하는 것

트리에서 수정 점 정의 내부의 목록에 수정 점 정의를 중첩하면 결과의 유형이 잘됩니다. 이것은 귀납적 유형으로 재귀를 중첩했을 때, 즉 재귀가와 같은 생성자를 통과 할 때의 일반적인 원리 list입니다.

Fixpoint size (t : LTree) : nat :=
  let size_l := (fix size_l (l : list LTree) : nat :=
                  match l with
                    | nil => 0
                    | h::r => size h + size_l r
                  end) in
  match t with Node l =>
    1 + size_l l
  end.

또는 이것을 더 간결하게 작성하려는 경우 :

Fixpoint size (t : LTree) : nat :=
  match t with Node l =>
    1 + (fix size_l (l : list LTree) : nat :=
          match l with
            | nil => 0
            | h::r => size h + size_l r
          end) l
  end.

(처음부터 누가 들었는지 전혀 모른다. 이것은 확실히 독립적으로 여러 번 발견되었다.)

일반 재귀 술어

보다 일반적으로 "적절한"유도 원리를 LTree수동으로 정의 할 수 있습니다. LTree_rect유도 원리 생성기는 유도 유형의 중첩되지 않은 엄격하게 긍정적 인 발생 만 이해하기 때문에 자동으로 생성 된 유도 원리 는 목록의 가설을 생략합니다.

LTree_rect = 
fun (P : LTree -> Type) (f : forall l : list LTree, P (Node l)) (l : LTree) =>
match l as l0 return (P l0) with
| Node x => f x
end
     : forall P : LTree -> Type,
       (forall l : list LTree, P (Node l)) -> forall l : LTree, P l

목록에 유도 가설을 추가합시다. 재귀 호출에서이를 수행하기 위해 목록 유도 원리를 호출하고 목록 내부의 작은 나무에 트리 유도 원리를 전달합니다.

Fixpoint LTree_rect_nest (P : LTree -> Type) (Q : list LTree -> Type)
                         (f : forall l, Q l -> P (Node l))
                         (g : Q nil) (h : forall t l, P t -> Q l -> Q (cons t l))
                         (t : LTree) :=
  match t as t0 return (P t0) with
    | Node l => f l (list_rect Q g (fun u r => h u r (LTree_rect_nest P Q f g h u)) l)
  end.

이유에 대한 답은 재귀 함수를 받아들이는 정확한 규칙에 있습니다. 이러한 규칙은 복잡한 경우 (예 : 데이터 유형에 중첩 된 재귀가있는 경우)와 건전성 사이의 미묘한 균형이 있기 때문에 미묘합니다. COQ 참조 설명서를 소개합니다 언어 대부분 공식적으로 정확한 정의와 함께,하지만 (COQ의 증거 언어 유도 구조물의 미적분학) 당신이 연구 논문으로 이동해야합니다 유도 및 coinduction에 대한 정확한 규칙을 원하는 경우, 이 주제에 대해 Eduardo Giménez의 [1].

Coq 매뉴얼부터 Fix규칙 표기법 으로 의 수정 점 정의를 갖습니다.에프나는엑스에프나는{에프1:에이1: =1;에프2:에이2: =2}

Γ1=(엑스:아르 자형이자형이자형)에이1=에이1=기음에이에스이자형(엑스,아르 자형이자형이자형,λ와이.1(에프2와이))Γ2=(:나는에스아르 자형이자형이자형)에이2=에이2=기음에이에스이자형(,나는에스아르 자형이자형이자형,λh아르 자형.2(에프1h)(에프2아르 자형))

에프j나는에프나는

  • 나는=1j=2 : 에서 l보다 구조적으로 작아야합니다 .tsize
  • 나는=2j=1hlsize_l
  • 나는=2j=2rlsize_l

왜 Coq 해석기 h보다 구조적으로 작지 않은 이유 는 l분명하지 않습니다. Coq-club 목록 [1] [2]에 대한 논의에서 이해하는 한, 이것은 통역사의 제한 사항이며 원칙적으로 해제 될 수 있지만 불일치가 발생하지 않도록 매우 신중합니다.

참고 문헌

코카 리코, 종료되지 않는 Coq 위키 : 상호 유도

Coq-Club 메일 링리스트 :

Coq 개발팀. Coq Proof Assistant : 참조 매뉴얼 . 버전 8.3 (2010). [ ] ch. 4 .

에두아르도 기 메네즈 재귀 체계로 보호 된 정의를 체계화 . 에서 Types'94 : 증거들 및 프로그램에 대한 유형 , LNCS 996 출판사 (Springer-Verlag), 1994 년 도이 : 10.1007 / 3-540-60579-7_3 [ 스프링 ]

에두아르도 기 메네즈 유형 이론의 구조 재귀 정의 . 에서 ICALP'98 : 절차 25 오토마타, 언어 및 프로그래밍에 관한 국제 콜로키움의. Springer-Verlag, 1998. [ PDF ]


7

이것은 다른 증거 보조원과 함께 해결할 수있는 더 좋은 방법이 있다고 생각하기 때문에 분명히 Coq와 관련된 문제입니다 (Agda를보고 있습니다)

처음 r에는 구조가 현재 처리하는 귀납적 정의에 불과하기 때문에 구조적으로 작은 것으로 인식되지 않았습니다 Fixpoint. 따라서 LTree하위 용어 인 경우에도 하위 용어 가 아닙니다 list.

그러나 목록 처리를 확장하면 작동합니다.

Fixpoint size t :=
  match t with
  | Node l => S
     ((fix size_l l :=
     match l with
     | nil => 0
     | cons t l => size_l l + size t
     end) l)
 end.

또는 보조 기능이 표준 라이브러리에 이미 존재하기 때문에 :

Require Import List.

Fixpoint size t :=
  match t with
  | Node l => S (fold_left (fun a t => a + size t) l 0)
  end.

솔직히 말해서 나는 왜 그것들이 Coq에 의해 받아 들여 졌는지 확실하지 않지만, 나는 그들이 기쁘다.

또한 자체적으로 포함 된 유도 유형을 정의하는 목록뿐만 아니라 더 자주 작동하는 솔루션도 있습니다. 이 경우에는size 기능을 수동으로 수 있습니다. (고정 점 두 개)

Inductive LTree : Set :=
  | Node : list_LTree -> LTree
with list_LTree : Set :=
  | LTree_nil : list_LTree
  | LTree_cons : LTree -> list_LTree -> list_LTree.

보다 복잡한 귀납적 정의에 문제가있는 경우 크기를 줄이는 인수를 사용할 수 있습니다. 그것은 가능하지만이 문제에 대해 성가시다 (그리고 나는 대부분의 문제에 대해 감히 말할 것이다)


오늘도 여전히 이해하지 못하는 것은 순진한 접근 방식이 작동하지 않는 이유입니다. 원칙적으로 이것은 Eduardo Giménez의 논문의 결과물이어야하지만 공제가 어디에서 깨어나는지는 알 수 없습니다. 이것은 기본 미적분학이 아닌 Coq 엔진의 한계 일 수 있습니다.
Gilles 'SO- 악마 중지'
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.