नेस्टेड घटकों के साथ एक प्रेरक प्रकार पर पुनरावर्ती परिभाषाएं


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निम्नलिखित व्याकरण के अनुरूप एक प्रेरक प्रकार है।

LTree::=|list(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

क्या यह विषय है? मुझे यकीन नहीं है; आइए मेटा पर इस पर चर्चा करें
गिल्स एसओ- बुराई को रोकना '

आप कुछ कम Coqy और अधिक mathy में समान फ़ंक्शन परिभाषा जोड़ सकते हैं? मुझे सिंटैक्स को समझने में परेशानी होती है।
राफेल

1
@ राफेल मैंने कोशिश की है, क्या यह अब बेहतर है? ईमानदारी से, यह प्रश्न Coq के लिए बहुत विशिष्ट है।
गिल्स एसओ- बुराई को रोकें '

जवाबों:


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 आप की जरूरत शोध पत्र पर पहुंच जाएंगे के बारे में सटीक नियम चाहते हैं, इस विषय पर एडुआर्डो गिमनेज़ [1]।

कोक मैनुअल के साथ शुरू, Fixनियम के अंकन में , हमारे पास की फिक्सपॉइंट परिभाषा हैएफमैंएक्समैं{1:1: =टी1;2:2: =टी2}

Γ1=(एक्स:एलटीआर)1=nटीटी1=सीरों(एक्स,एलटीआर,λyजी1(2y))Γ2=(एल:एलमैंरोंटीएलटीआर)2=nटीटी2=सीरों(एल,एलमैंरोंटीएलटीआर,λआरजी2(1)(2आर))

जेटीमैंमैं

  • मैं=1जे=2ltsize
  • मैं=2जे=1hlsize_l
  • मैं=2जे=2rlsize_l

Coq दुभाषिया के अनुसार hसंरचनात्मक रूप से छोटा क्यों नहीं है इसका कारण lमेरे लिए स्पष्ट नहीं है। जहां तक ​​मैं कोक्-क्लब की सूची [1] [2] पर चर्चा से समझता हूं, यह दुभाषिया में एक प्रतिबंध है, जिसे सिद्धांत रूप में उठाया जा सकता है, लेकिन एक असंगति को पेश करने से बचने के लिए बहुत सावधानी से।

संदर्भ

कोकोरिको, नॉनटार्मिंग कोक विकी: म्यूचुअल इंडक्शन

कोक-क्लब मेलिंग सूची:

द कोक डेवलपमेंट टीम। द कॉक प्रूफ असिस्टेंट: रेफरेंस मैनुअल । संस्करण 8.3 (2010)। [ वेब ] ch। ४

एडुआर्डो जिमनेज़। पुनरावर्ती योजनाओं के साथ संरक्षक परिभाषाओं को संहिताबद्ध करना । में Types'94: सबूत और कार्यक्रम के लिए प्रकार , LNCS 996. स्प्रिंगर-वर्लग, 1994 डीओआई: 10.1007 / 3-540-60579-7_3 [ स्प्रिंगर ]

एडुआर्डो जिमनेज़। टाइप थ्योरी में संरचनात्मक पुनरावर्ती परिभाषाएँ । में ICALP'98: 25 वीं ऑटोमेटा, बोली और प्रोग्रामिंग पर अंतर्राष्ट्रीय वार्तालाप की कार्यवाही। स्प्रिंगर-वर्लग, 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.

सच कहूँ तो मुझे यकीन नहीं है कि क्यूक द्वारा स्वीकार किए जाते हैं, लेकिन मुझे यकीन है कि वे खुश हैं।

एक समाधान भी है जो अधिक बार और न केवल सूचियों के लिए काम करता है: एक स्व-निहित आगमनात्मक प्रकार को परिभाषित करना। इस मामले में आप अपने sizeफ़ंक्शन को मैन्युअल रूप से परिभाषित कर सकते हैं । (दो तय बिंदुओं के साथ)

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

ध्यान दें कि यदि आपको अधिक जटिल प्रेरक परिभाषाओं के लिए समस्या है, तो आप एक आकार-घटते तर्क का उपयोग कर सकते हैं। यह संभव है लेकिन इस समस्या के लिए बोझिल (और मैं ज्यादातर समस्याओं के लिए कहने की हिम्मत करूंगा)


मुझे आज भी समझ में नहीं आता है कि भोले दृष्टिकोण से काम क्यों नहीं होता है। सिद्धांत रूप में, यह एडुआर्डो गिमनेज़ के पेपर का एक परिणाम होना चाहिए, लेकिन मैं नहीं देखता कि कटौती कहाँ टूटती है; यह अंतर्निहित पथरी के बजाय Coq इंजन की एक सीमा हो सकती है।
गिल्स एसओ- बुराई को रोकना '
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.