ความหลากหลายและประเภทข้อมูลอุปนัย


10

ฉันอยากรู้. ฉันได้ทำงานกับประเภทข้อมูลนี้ในOCaml :

type 'a exptree =
  | Epsilon
  | Delta of 'a exptree * 'a exptree
  | Omicron of 'a
  | Iota of 'a exptree exptree

ซึ่งสามารถจัดการได้โดยใช้ฟังก์ชั่นวนซ้ำอย่างชัดเจน (คุณลักษณะที่ถูกเพิ่มเข้ามาเมื่อไม่นานมานี้) ตัวอย่าง:

let rec map : 'a 'b. ('a -> 'b) -> 'a exptree -> 'b exptree =
  fun f ->
    begin function
    | Epsilon -> Epsilon
    | Delta (t1, t2) -> Delta (map f t1, map f t2)
    | Omicron t -> Omicron (f t)
    | Iota tt -> Iota (map (map f) tt)
    end

แต่ฉันไม่สามารถนิยามได้ในCoq :

Inductive exptree a :=
  | epsilon : exptree a
  | delta : exptree a -> exptree a -> exptree a
  | omicron : a -> exptree a
  | iota : exptree (exptree a) -> exptree a
.

Coqกำลังส่งเสียงครวญคราง มันไม่ชอบนวกรรมิกตัวสุดท้ายและพูดบางสิ่งที่ฉันไม่เข้าใจหรือเห็นด้วยอย่างสมบูรณ์:

Error: Non strictly positive occurrence of "exptree" in "exptree (exptree a) -> exptree a".

สิ่งที่ฉันสามารถเข้าใจได้คือประเภทอุปนัยที่ใช้การปฏิเสธในคำจำกัดความของพวกเขาเช่นtype 'a term = Constructor ('a term -> …)ถูกปฏิเสธเพราะพวกเขาจะนำไปสู่สัตว์ที่ไม่ได้ก่อตั้งขึ้นอย่างน่าเกลียดเช่น (ไม่พิมพ์) terms- ข้อตกลง อย่างไรก็ตามexptreeประเภทข้อมูลนี้ดูเหมือนจะไม่น่ากลัวพอ: ดูที่คำจำกัดความของOCamlอาร์กิวเมนต์ของมัน'aไม่เคยถูกใช้ในตำแหน่งเชิงลบ

ดูเหมือนว่าCoqอยู่ตรงนี้มากเกินไป ดังนั้นจึงมีปัญหากับประเภทข้อมูลอุปนัยเฉพาะนี้หรือไม่? หรือCoqอาจจะได้รับอนุญาตมากกว่านี้เล็กน้อย?

นอกจากนี้แล้วผู้ช่วยพิสูจน์คนอื่น ๆ พวกเขาสามารถรับมือกับคำจำกัดความอุปนัยเช่นนั้นได้หรือไม่?

คำตอบ:


9

สิ่งนี้มีอยู่ในรายชื่อผู้รับจดหมาย Coq หลายครั้ง แต่ฉันไม่เคยเห็นคำตอบที่แน่ชัด Coq ไม่ใช่แบบทั่วไปอย่างที่ควรจะเป็น กฎใน (Coquand, 1990) และ (Giménez, 1998) (และวิทยานิพนธ์ระดับปริญญาเอกของเขา) เป็นเรื่องทั่วไปมากขึ้นและไม่จำเป็นต้องมีผลบวกอย่างเข้มงวด Positivity พอไม่พอ แต่เมื่อคุณออกไปข้างนอกSet; ตัวอย่างนี้เกิดขึ้นในการสนทนาหลายครั้ง:

Inductive Big : Type := B : ((B -> Prop) -> Prop) -> Big.

ด้วยโครงสร้างข้อมูลธรรมดาเช่นคุณประเภทอุปนัยจะไม่ทำให้เกิดปัญหาอื่นนอกจากการทำให้เกิดการใช้งานที่ซับซ้อนมากขึ้น

มีวิธีทั่วไปในการกำหนดประเภทเช่นนี้กำหนดไว้เป็น fixpoint ของพหุนาม:

F=ϵ+δ(F×F)+οid+FF

แทนที่จะพยายามกำหนดฟังก์ชันให้นิยามตระกูลของประเภท\ นี่หมายถึงการเพิ่มพารามิเตอร์จำนวนเต็มให้กับประเภทที่เข้ารหัสจำนวนการแต่งเพลงของตัวเอง ( , , , ฯลฯ ) และตัวสร้างการฉีดเสริมเพื่อเปิดเข้าaexptree:aexptree(a)exptree,exptreeexptree,exptreeexptreeexptree,exptree0(a)=aexptree1(a)=exptree(a)exptree2(a)=exptree(exptree(a))aexptree0(a)=a

Inductive et : nat -> Type -> Type :=
  | alpha : forall a, a -> et 0 a                      (*injection*)
  | omicron : forall n a, et n a -> et (S n) a         (**)
  | epsilon : forall (S n) a, et (S n) a
  | delta : forall n a, et (S n) a -> et (S n) a -> et (S n) a
  | iota : forall n a, et (S (S n)) a -> et (S n) a
.

คุณสามารถกำหนดค่าและดำเนินการต่อได้ Coq มักจะสามารถอนุมานเลขชี้กำลัง Set Implicit Argumentsจะทำให้คำจำกัดความเหล่านี้สวยขึ้น

Definition exptree := et 1.
Definition et1 : exptree nat :=
  delta _ _ (omicron _ _ (alpha _ 42)) (epsilon _ _).
Definition et2 : exptree nat := iota _ _ (omicron _ _ et1).

คุณอาจต้องการที่จะลดการโต้แย้งโดยที่ 1 เพื่อให้เป็นexptree et 0นี้จะเอาจำนวนมากS nในความหมายซึ่งอาจทำให้การพิสูจน์บางอย่างได้ง่ายขึ้น แต่ก็ต้องแยกกรณีที่เริ่มต้นจากกรณีการเกิดซ้ำในทุกสร้างที่ใช้เวลาในอาร์กิวเมนต์ (แทนการเพิ่มนวกรรมิกฉีดเพียงครั้งเดียวสำหรับ) ในตัวอย่างนี้มีเพียงตัวสร้างเดียวที่จะแยกดังนั้นนี่ควรเป็นตัวเลือกที่ดีaa

Inductive et : nat -> Type -> Type :=
  | omicron_0 : forall a, a -> et 0 a
  | omicron_S : forall n a, et n a -> et (S n) a
  | epsilon : forall n a, et n a
  | delta : forall n a, et n a -> et n a -> et n a
  | iota : forall n a, et (S n) a -> et n a
.
Definition exptree := et 0.
Definition et1 : exptree nat :=
  delta _ _ (omicron_0 _ 42) (epsilon _ _).
Definition et2 : exptree nat :=
  (iota _ _ (omicron_S _ _ et1)).

ผมคิดว่านี่เป็นหลักการเดียวกันที่นำเสนอในรูปแบบทั่วไปมากขึ้นโดยราล์ฟ Mattes

อ้างอิง

Thierry Coquand และ Christine Paulin กำหนดประเภท Inductively ในการดำเนินการของ COLOG'88 , LNCS 417, 1990 [ Springer ] [ Google ]

Eduardo Giménez โครงสร้างการซ้ำคำนิยามในประเภททฤษฎี ในICALP'98: การดำเนินการประชุมนานาชาติครั้งที่ 25 เรื่อง Automata ภาษาและการเขียนโปรแกรม Springer-Verlag, 1998. [ PDF ]



6

หนึ่งในสิ่งแรกที่ Coq ทำคือการสร้างหลักการอุปนัยที่เกี่ยวข้องกับประเภทอุปนัยที่คุณเพิ่งกำหนดและทำความเข้าใจกับหลักการอุปนัยพื้นฐานเป็นการออกกำลังกายที่ดี

ยกตัวอย่างเช่นจะสร้างหลักการเหนี่ยวนำO : nat | S : nat -> natP O -> (∀ n, P n -> P (S n)) -> ∀ n, P n

หลักการอุปนัยสอดคล้องกับiotaอะไร? มันดูเหมือนว่ามีกริยาไม่Pว่าจะสามารถที่จะพูดคุยเกี่ยวกับP tและP (iota t)เพราะมันควรจะพูดคุยเกี่ยวกับexptree a, exptree (exptree a), exptree (exptree (exptree a))...

นอกจากนี้ยังOmicronทำสิ่งเดียวกัน แต่ประเภทมีขนาดเล็กลงในแต่ละครั้ง คุณควรรู้สึกว่าการอ้างอิงทั้งประเภทที่เล็กกว่าและใหญ่กว่านั้นจะทำให้สิ่งต่าง ๆ ยุ่งเหยิง (ที่กล่าวว่าOmicronเป็นวิธีที่ถูกต้อง)

นั่นไม่ใช่เกณฑ์ที่แน่นอนที่ระบุว่าทำไมคำนิยามไม่ควรยอมรับ แต่นี่อธิบายว่าทำไมมันถึงรู้สึกผิดกับฉัน

exptreeดูเหมือนว่าคุณกำลังสร้างไวยากรณ์สำหรับการแสดงออกสิ่งที่โดยทั่วไปจะไม่ว่า recursive คุณต้องการความช่วยเหลือไหม?

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.