Yuvalanmış bileşenler içeren endüktif tip üzerinde özyinelemeli tanımlar


21

Yuvalanmış, ancak kesinlikle olumlu bir yerde bazı yinelemeli olaylara sahip bir endüktif türü düşünün. Örneğin, çocukları depolamak için genel liste veri yapısı kullanan düğümlerle sonlu dallara sahip ağaçlar.

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

Ağaçlar ve ağaç listeleri üzerinde tekrarlayarak bu ağaçlar üzerinde özyinelemeli bir işlev tanımlamanın naif yolu işe yaramaz. sizeDüğüm sayısını hesaplayan işleve bir örnek .

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.

Bu tanım yanlış oluşturulmuştur (hata mesajı alıntılanmıştır):

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

rAçıkça bir alt ara olmasına rağmen tanım neden yanlış biçimlendirilmiş l? Böyle bir veri yapısı üzerinde özyinelemeli işlevler tanımlamanın bir yolu var mı?


Coq sözdiziminde akıcı değilseniz: LTreeaşağıdaki dilbilgisine karşılık gelen endüktif bir tiptir.

LTree::=|list(LTree)

sizeFonksiyonu ağaçlar ve listeler üzerinde indüksiyonla tanımlamaya çalışıyoruz . OCaml'de bu şöyle olur:

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

Bu konu üzerinde mi? Emin değilim; bunu Meta'da tartışalım .
Gilles 'SO- kötü'

Daha az Coqy ve daha fazla mathy'ye eşdeğer işlev tanımları ekleyebilir misiniz? Sözdizimini anlamakta güçlük çekiyorum.
Raphael

1
@Raphael denedim, şimdi daha iyi mi? Dürüst olmak gerekirse, bu soru Coq'a oldukça özgüdür.
Gilles 'SO- kötü olmayı kes'

Yanıtlar:


14

Ne çalışıyor

Düzeltme noktası tanımını, ağaçlardaki düzeltme noktası tanımının içindeki listelere yerleştirirseniz, sonuç iyi yazılır. Bu, özyinelemeli bir türde özyinelemeyi iç içe geçirdiğinizde, yani özyineleme gibi bir yapıcıdan geçtiğinde genel bir ilkedir 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.

Veya bunu daha ters yazmayı tercih ediyorsanız:

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.

(İlk başta kimi duyduğum hakkında hiçbir fikrim yok; bu kesinlikle birçok kez bağımsız olarak keşfedildi.)

Genel özyineleme yüklemi

Daha genel olarak, “uygun” indüksiyon prensibini LTreemanuel olarak tanımlayabilirsiniz . Otomatik olarak oluşturulan indüksiyon prensibi LTree_rectlistedeki hipotezi atlar, çünkü indüksiyon prensibi jeneratörü sadece endüktif tipin iç içe olmayan kesinlikle pozitif oluşumlarını anlar.

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

Listelere indüksiyon hipotezini ekleyelim. Özyinelemeli çağrıda yerine getirmek için, liste indüksiyon prensibi olarak adlandırırız ve onu listenin içindeki küçük ağaç üzerinde ağaç indüksiyon prensibine geçiririz.

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.

Niye ya

Nedeninin cevabı, özyinelemeli işlevleri kabul etmek için kesin kurallarda yatmaktadır. Bu kurallar ince performans gösterir, çünkü karmaşık vakalara izin verilmesi (bu gibi, veri tipinde iç içe özyineleme ile) ve sessizlik arasında hassas bir denge vardır. Coq referans kılavuzu tanıttı dil çoğunlukla resmen kesin olarak tanımlanmasıyla birlikte, ancak (Coq kanıtı dildir endüktif inşaatlar hesabı,) sen araştırma makaleleri gitmek gerek edeceğiz indüksiyon ve coinduction ilişkin kesin kurallar istiyorsanız, bu konuda Eduardo Giménez'nin [1].

Coq kılavuzundan başlayarak, Fixkuralın gösterilmesinde, düzeltme noktası tanımına sahibizFixfi{f1:A1:=t1;f2:A2:=t2}

Γ1=(x:LTree)A1=natt1=case(x,LTree,λy.g1(f2y))Γ2=(l:listLTree)A2=natt2=case(l,listLTree,λhr.g2(f1h)(f2r))

fjtifi

  • i=1j=2ltsize
  • i=2j=1hlsize_l
  • i=2j=2rlsize_l

Coq yorumlayıcısına göre hyapısal olarak daha küçük olmamasının sebebi lbenim için net değil. Coq-club listesindeki tartışmalardan anladığım kadarıyla [1] [2], bu, prensipte kaldırılabilecek bir tutarsızlıktır, ancak tutarsızlık getirmekten kaçınmak için çok dikkatli bir şekilde.

Referanslar

Cocorico, bitmeyen Coq wiki: Karşılıklı Tümevarım

Coq-Club posta listesi:

Coq Geliştirme Ekibi. Coq Proof Assistant: Referans Kılavuzu . Sürüm 8.3 (2010). [ web ] ch. 4 .

Eduardo Giménez. Korumalı tanımların özyinelemeli şemalarla kodlanması . Gelen Types'94: Düzeltmeler ve Programlar türleri , LNCS 996, Springer-Verlag, 1994, doi: 10.1007 / 3-540-60579-7_3 [ Springer ]

Eduardo Giménez. Tip Teorisinde Yapısal Özyinelemeli Tanımlar . In ICALP'98: Tutanakları 25 Özdevinir, Dil ve Programlama Uluslararası Kolokyumu arasında. Springer-Verlag, 1998. [ PDF ]


7

Bu açıkça Coq'a özgü bir problem çünkü diğer bazı kanıt asistanlarıyla dolaşmanın daha güzel yolları olduğuna inanıyorum (Agda'ya bakıyorum)

İlk başta ryapısal olarak daha küçük olarak kabul edilmediğini düşündüm , çünkü yapı sadece şu anda ele alınan endüktif tanımla ilgilidir Fixpoint: bu yüzden bu bir alt LTreedönem olsa bile bir alt listdönem değildir.

Ancak listenin işlenmesini genişletirseniz, çalışır:

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.

Veya yardımcı fonksiyon standart kütüphanede zaten mevcut olduğundan:

Require Import List.

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

Dürüst olmak gerekirse, bunların neden Coq tarafından kabul edildiğinden emin değilim, ama eminim.

Ayrıca, sadece listeler için değil, daha sık çalışan bir çözüm de vardır: bağımsız bir endüktif tür tanımlamak. Bu durumda sizeişlevinizi manuel olarak tanımlayabilirsiniz . (iki sabitleme noktalı)

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

Daha karmaşık tümevarımsal tanımlamalar için sorun yaşıyorsanız, boyutu azaltan bir bağımsız değişken kullanabilirsiniz. Bu mümkün ama bu sorun için hantal (ve çoğu problem için söylemeye cesaret edeceğim)


Bugün hala anlamadığım şey, saf yaklaşımın neden işe yaramadığı. Prensip olarak, bu Eduardo Giménez'nin makalesinin bir sonucu olmalı, ancak kesinti nerede kırıldığını görmüyorum; bu temel hesaptan ziyade Coq motorunun bir sınırlaması olabilir.
Gilles 'SO- kötü olmayı bırak'
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.