Paramorfizm nedir?


95

Bu klasik makaleyi okurken paramorfizmlere takılıp kaldım. Ne yazık ki bölüm oldukça ince ve Wikipedia sayfası hiçbir şey söylemiyor.

Haskell çevirim:

para :: (a -> [a] -> b -> b) -> b -> [a] -> b
para f base = h
  where
    h []       =   base
    h (x:xs)   =   f x xs (h xs)

Ama bunu anlamıyorum - Yazı tipi imzası veya istenen sonuç için herhangi bir sezgim yok.

Paramorfizm nedir ve uygulamadaki bazı yararlı örnekler nelerdir?


Evet, bu soruları gördüm , ancak bunlar paramorfizmaları doğrudan kapsamıyor ve sadece referans olarak yardımcı olabilecek kaynaklara işaret ediyor , ancak öğrenme materyalleri olarak değil.


1
para f base xs = foldr (uncurry f) base $ zip xs (tail $tails xs), benim için.
Daniel Fischer

Göre bu wiki sayfasından , paramorphisms "endüktif veri türleri üzerinde modeli ilkel özyineleme". Bu bir şey ifade ediyor mu / yardım ediyor mu?
huon

4
Jeremy Gibbons'ın bu sorulardan birine yaptığım bir yorumda işaret ettiğim "Fisyon" makalesi çok faydalı bir öğrenme materyali. cs.ox.ac.uk/jeremy.gibbons/publications/fission.pdf Çok sayıda özyineleme modeliyle çok net bir şekilde çalışır.
stephen tetley

1
Daniel'in yeniden yazımı şu şekilde basitleştirilebilir para f base xs = foldr g base (init $ tails xs) where g (x:xs) = f x xs . Bu Common Lisp'imaplist hatırlatıyor .
Will Ness

Yanıtlar:


109

Evet, bu para. Katamorfizm ile karşılaştırın veya foldr:

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

para  c n (x : xs) = c x xs (para c n xs)
foldr c n (x : xs) = c x    (foldr c n xs)
para  c n []       = n
foldr c n []       = n

Bazı insanlar, katamorfizmlerin ( foldr) "yineleme" olmasının aksine, paramorfizmaları "ilkel özyineleme" olarak adlandırırlar .

Nerede foldrbireyin iki parametre (listenin kuyruğu burada,) giriş verilerinin her özyinelemeli altnesnesi için yinelemeli hesaplanan değer verilir, para'in parametreleri orijinal subobject ve ondan yinelemeli hesaplanan değeri hem olsun.

Güzel bir şekilde ifade edilen örnek bir işlev para, bir listenin uygun yeterliklerinin toplanmasıdır.

suff :: [x] -> [[x]]
suff = para (\ x xs suffxs -> xs : suffxs) []

Böylece

suff "suffix" = ["uffix", "ffix", "fix", "ix", "x", ""]

Muhtemelen daha basit, yine de

safeTail :: [x] -> Maybe [x]
safeTail = para (\ _ xs _ -> Just xs) Nothing

burada "eksiler" dalı, yinelemeli olarak hesaplanan argümanını görmezden gelir ve sadece kuyruğu geri verir. Tembel olarak değerlendirildiğinde, özyinelemeli hesaplama asla gerçekleşmez ve kuyruk sabit zamanda çıkarılır.

Sen tanımlayabilirsiniz foldrkullanarak paraoldukça kolay; o tanımlamak için biraz daha yanıltıcıdır paragelen foldr, ama kesinlikle mümkündür ve herkes nasıl yapıldığını bilmeli!

foldr c n =       para  (\ x  xs  t ->           c x    t)       n
para  c n = snd . foldr (\ x (xs, t) -> (x : xs, c x xs t)) ([], n)

Tanımlamanın hile paraile foldrbir yeniden inşa etmektir kopyasını biz orijinal erişimi olmasına rağmen, her adımda kuyruk bir kopyasını erişebilmek böylece, orijinal verilerin. Sonunda, sndgirdinin kopyasını atar ve sadece çıktı değerini verir. Çok verimli değil, ancak tamamen ifade ile ilgileniyorsanız, parasize bundan fazlasını vermez foldr. Bu foldrkodlanmış sürümünü kullanırsanız para, safeTailher şeyden önce kuyruk elemanını elemanlara kopyalayarak doğrusal zaman alacaktır.

İşte bu kadar: listenin kuyruğuna ve ondan hesaplanan değere anında erişim sağlayan paradaha kullanışlı bir sürümüdür foldr.

Genel durumda, bir functor'un özyinelemeli sabit noktası olarak oluşturulan bir veri türü ile çalışma

data Fix f = In (f (Fix f))

var

cata :: Functor f => (f         t  -> t) -> Fix f -> t
para :: Functor f => (f (Fix f, t) -> t) -> Fix f -> t

cata phi (In ff) = phi (fmap (cata phi) ff)
para psi (In ff) = psi (fmap keepCopy   ff) where
  keepCopy x = (x, para psi x)

ve yine, ikisi de aynı "kopya yap" numarasıyla paratanımlanarak karşılıklı olarak tanımlanabilircata

para psi = snd . cata (\ fxt -> (In (fmap fst fxt), psi fxt))

Yine, paradaha anlamlı değildir cata, ancak girdinin alt yapılarına kolay erişime ihtiyacınız varsa daha kullanışlıdır.

Düzenleme: Başka bir güzel örnek hatırladım.

Fix TreeFNereye göre verilen ikili arama ağaçlarını düşünün

data TreeF sub = Leaf | Node sub Integer sub

ve ikili arama ağaçları için eklemeyi önce a cata, sonra a olarak tanımlamayı deneyin para. paraHer düğümde bir alt ağaca eklemeniz, ancak diğerini olduğu gibi korumanız gerekeceğinden sürümü çok daha kolay bulacaksınız .

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.