SORU
7 Mayıs 2013, Salı


Bir tür liste dışında kat, ne demek?

Tek bağlı bir liste düşünün. Gibi bir şey görünüyor

data List x = Node x (List x) | End

Doğal katlama gibi bir işlev tanımlayın

reduce :: (x -> y -> y) -> y -> List x -> y

, reduce f x0 bir anlamda değiştirir f 29 *Her x0 End her. Bu Başlangıcı olarak ifade ederkat.

Şimdi düşünün basit bir ikili ağaç:

data Tree x = Leaf x | Branch (Tree x) (Tree x)

Benzer şekilde doğal böyle bir fonksiyonu olarak tanımlamak için

reduce :: (y -> y -> y) -> (x -> y) -> Tree x -> y

Dikkat edinbuazalma oldukça farklı bir karakteri var; liste tabanlı bir doğal olarak sıralı ise, ağaç tabanlı bu yeni bir böl ve fethet hissediyorum daha fazla. Orada par birkaç combinators atma düşünebiliriz bile. (Liste sürümünde böyle bir şey koyar mısınız?)

Benim sorum: bu fonksiyonu hala bir olarak sınıflandırılır"", yoksa başka bir şey mi? kat. (Ve eğer öyleyse, ne oldu?)

Herkes katlanır bahsettiği zaman aslında, onlar her zaman katlanır hakkında konuşmaklistelerdoğal olarak sıralı. "Sıralı" ne kat tanımı var mı, yoksa bu sadece katlanır. yaygın olarak kullanılan en örnek rastlantısal bir özelliği olup olmadığını bir parçası olup olmadığını merak ediyorum

CEVAP
7 Mayıs 2013, Salı


Bir Her Durum için Katlayın

Aslında farklı bir sürü için geçerli olan katlama genel bir kavram bulabiliriz. Yani, sistematik listeler, ağaçlar ve daha fazlası için fold bir fonksiyon tanımlayabiliriz.

fold bu genel kavram @pelotom yaptığı açıklamada söz konusu catamorphisms karşılık gelir.

Yinelemeli Tipler

Anahtar ınsight fold bu işlevler yoluyla belirlenirözyinelemelitürleri. Özellikle:

data List a = Cons a (List a) | Nil
data Tree a = Branch (Tree a) (Tree a) | Leaf a

Bu tür İki netCons ve Branch durumda Tree--List tekrar eder.

Puan Sabit

Sadece fonksiyonlar gibi, bu tür sabit noktaları kullanarak yazabiliriz. fix tanımı unutma

fix f = f (fix f)

Aslında ekstra yapıcı bir sarıcı olmak zorunda dışında bu tür için çok benzer bir şey yazabilir miyiz:

newtype Fix f = Roll (f (Fix f))

fix bir sabit nokta tanımlar gibiişlevibu bir sabit nokta tanımlarfunctor. Tüm özyinelemeli tipleri Fix bu yeni türünü kullanarak ifade edebiliriz.

Bu bize aşağıdaki gibidir: List türleri yeniden yazmak için izin verir

data ListContainer a rest = Cons a rest | Nil
type List a = Fix (ListContainer a)

Esasen, Fix bize keyfi derinliklerine ListContainers yuva sağlar. Sahip olmamız için:

Roll Nil
Roll (Cons 1 (Roll Nil))
Roll (Cons 1 (Roll (Cons 2 (Roll Nil))))

[], [1] [1,2] sırasıyla karşılık.

ListContainer Functor bir olduğunu görmek kolaydır:

instance Functor (ListContainer a) where
  fmap f (Cons a rest) = Cons a (f rest)
  fmap f Nil           = Nil

List 60 *eşleme gayet doğal bence: açıkça recursing yerine, özyinelemeli parçası olan bir değişken yapıyoruz. O zaman sadece Fix değişken uygun olarak doldurmak için kullanın.

Tree benzer bir türü de yazabiliriz.

"Açılması" Sabit Noktalar

Neden önemsiyoruz? fold tanımlayabilirizkeyfitür yazılı Fix kullanarak. Özellikle:

fold :: Functor f => (f a -> a) -> (Fix f -> a)
fold h = h . fmap (fold h) . unRoll
  where unRoll (Roll a) = a

Tüm kat "yuvarlandı" türü bir kerede, sonuç her zaman için bir işlevi uygulamak. aç aslında yok. Bu "sağlar, bizi tanımlayan" herhangi bir özyinelemeli türü için katlayın ve düzgün ve doğal bir kavram genelleme. çözümü

Bu liste, örneğin, bu gibi çalışır:

  1. Her adımda, Roll Cons Nil bir de almamız çıkar
  2. Listede adı fmap kullanarak geri kalanını biz recurse.
    1. Nil durumunda, fmap (fold h) Nil = Nil, bu yüzden biz sadece 73* *dönüş.
    2. Cons durumunda, fmap sadece listenin geri kalanı üzerinde kat devam ediyor.
  3. Sonunda fold iç içe geçmiş bir sürü arama 78 **standardı gibi Nil--bir bitiş.

Karşılaştırma Türleri

Şimdi iki kat fonksiyonları türleri bakmak sağlar. , 79**: ilk

foldr :: (a -> b -> b) -> b -> [a] -> b

Şimdi 82**, fold uzman:

fold :: (ListContainer a b -> b) -> (Fix (ListContainer a) -> b)

İlk başta, bu tamamen farklı görünüyor. Ancak masaj yaparak biraz, hepsi aynı gösterebiliriz. foldr ilk iki argümanın a -> b -> b 86*. Bir fonksiyon ve bir sabit var. () -> b b düşünebiliriz. Şimdi _ () a -> b iki fonksiyonları _ -> b var. Hayatı daha basit hale getirmek için, ikinci işlevi bize (a, b) -> b köri izin veriyor. Şimdi bir olarak yazabiliriztekfonksiyonu Either kullanarak:

Either (a, b) () -> b

Bu gerçek f :: a -> c ve her zaman aşağıdaki yazabiliriz g :: b -> c verilen: çünkü

h :: Either a b -> c
h (Left a) = f a
h (Right b) = g b

Şimdi foldr olarak görebiliriz:

foldr :: (Either (a, b) () -> b) -> ([a] -> b)

(Hep böyle -> parantez içine doğru ilişkilendirilebilir oldukları sürece eklemek ücretsizdir.)

Şimdi ListContainer bakalım. Bu tip iki durum vardır: hiçbir bilgi taşıyan Nil ve de a ve b. bir olan Cons, () 109 *yazabiliriz:* 110*, gibi gibi başka bir yol, 107 ** konur

type ListContainer a rest = Either (a, rest) ()

Açıkça bu foldr ben yukarıda kullanılan aynı. Şimdi var:

foldr :: (Either (a, b) () -> b) -> ([a] -> b)
fold  :: (Either (a, b) () -> b) -> (List a -> b)

Yani, aslında, bu tür aynı şeyi yazma izomorfik ... sadece farklı yolları vardır! Bu oldukça serin olduğunu düşünüyorum.

Eğer türleriyle akıl yürütme bu tür hakkında daha fazla şey öğrenmek istiyorsanız (bir yan not olarak, The Algebra of Algebraic Data Types, sadece bu konuda blog yazıları güzel bir dizi göz atın.)

Ağaçlar için geri

Yani, türler sabit noktalar olarak yazılmış fold jenerik tanımlayabiliriz nasıl gördük. Ayrıca bu doğrudan listeler için foldr nasıl karşılık geldiğini gördük. Şimdi ikinci örnek olarak, ikili ağaç görünüm sağlar. Tipi var:

data Tree a = Branch a (Tree a) (Tree a) | Leaf a

yukarıda yaptığım kurallara uyarak bu Fix kullanarak yazabiliriz: a tipi değişken kısım: özyinelemeli değiştirdik

data TreeContainer a rest = Branch rest rest | Leaf a
type Tree a = Fix (TreeContainer a)

Şimdi bir ağaç 119**:

fold :: (TreeContainer a b -> b) -> (Tree a -> b)

foldTree orijinal bu gibi görünüyor:

foldTree :: (b -> b -> b) -> (a -> b) -> Tree a -> b

foldTree iki işlevi kabul eder; önce ve sonra Either tımar kullanarak: birine birleştireceğiz

foldTree :: (Either (b, b) a -> b) -> (Tree a -> b)

Ayrıca Either (b, b) a TreeContainer a b izomorfik olduğunu nasıl görebiliriz. Ağaç kaba sahip iki vaka:* *128, bs Leaf, 131* *birini içeren iki içeren.

Bu tür listesi örnek olarak aynı şekilde izomorfik olan kat.

Genelleme

Kesin bir dizi ortaya çıktı. Normal özyinelemeli veri türü dikkate alındığında, sistematik bir şekilde bizi bir functor sabit bir nokta olarak türünü ifade etmelerini sağlayan türü, olmayan özyinelemeli bir sürümünü oluşturabilirsiniz. Bu mekanik olarak tüm bu farklı aslında ... fold fonksiyonları ile, muhtemelen tüm işlemi otomatik olarak yapabiliriz böyle DZD Jenerik falan kullanarak bulabiliriz anlamına gelir.

Bir anlamda, bu gerçekten farklı türleri için fold farklı işlevlere sahip değiliz anlamına gelir. Daha doğrusu, olan fold tek bir işlevi varçokpolimorfik.

Daha fazla

Ben ilk tam a talk Conal Elliott tarafından verilen bu fikirleri anlaşılır. Bu daha ayrıntılı gider ve de 136* * * çift ** 135, bahsediyor.

Eğer bu tür şeylere dalmak istiyorsanız biledaha fazladerinden, "Functional Programming with Bananas, Lenses, Envelopes and Barbed Wire" paper fantastik okuyun. Diğer şeyler arasında, bu kavramları "" ve "anamorphisms" hangi kıvrımlar ve izlerken karşılık gelir. catamorphisms tanıttı

Cebir (ve Coalgebras)

Ayrıca, dayanamıyorum ekleme Eklentisi için kendimi :P. görebilirsiniz bazı ilginç benzerlikler arasındaki yolu kullanıyoruz Either burada ve ne zaman konuşmak hakkında algebras başka bir cevap.

Aslında fold ve Cebir arasında derin bir bağ vardır; ayrıca, unfold--fold--söz konusu çift cebiri çift olan coalgebras bağlı. Önemli fikir cebirsel veri türleri için "ilk cebiri" da cevabımı geri kalanı özetlendiği gibi kıvrımlar tanımlayın. karşılık gelen.

fold genel türü bu bağlantıda görebilirsiniz:

fold :: Functor f => (f a -> a) -> (Fix f -> a)

Çok tanıdık geldi f a -> a terim! F-Cebir gibi bir şey olarak tanımlandı: bir hatırlayın

class Functor f => Algebra f a where
  op :: f a -> a

fold gibi düşünebiliriz yani:

fold :: Algebra f a => Fix f -> a

Esasen, fold bize "" yapıları Cebir kullanılarak tanımlanan. özetlemek sağlar

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • Dion Coulls

    Dion Coulls

    16 AĞUSTOS 2006
  • Metheud

    Metheud

    9 EYLÜL 2006
  • TomSka

    TomSka

    30 Mayıs 2006