हाँ, वह है para
। कायापलट के साथ तुलना करें, या 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
कुछ लोग प्रतिरूपता को "आदिम पुनरावृत्ति" कहते हैं, इसके विपरीत कैटामोर्फिज्म ( foldr
) "पुनरावृति" होता है।
जहां foldr
दो मापदंडों को इनपुट डेटा के प्रत्येक पुनरावर्ती सबोबिज के लिए एक पुनरावर्ती संगणित मूल्य दिया जाता है (यहां, यह सूची की पूंछ है), para
पैरामीटर को मूल उपसमूह और मूल्य दोनों से पुनरावर्ती रूप से गणना की जाती है।
एक उदाहरण फ़ंक्शन जिसे अच्छी तरह से व्यक्त किया गया para
है वह किसी सूची के उचित प्रत्ययों का संग्रह है।
suff :: [x] -> [[x]]
suff = para (\ x xs suffxs -> xs : suffxs) []
ताकि
suff "suffix" = ["uffix", "ffix", "fix", "ix", "x", ""]
संभवतः सरल अभी भी है
safeTail :: [x] -> Maybe [x]
safeTail = para (\ _ xs _ -> Just xs) Nothing
जिसमें "कंस" शाखा अपने पुनरावर्ती संगणित तर्क की उपेक्षा करती है और बस पूंछ वापस देती है। आलसी का मूल्यांकन, पुनरावर्ती अभिकलन कभी नहीं होता है और पूंछ को निरंतर समय में निकाला जाता है।
आप काफी आसानी से परिभाषित foldr
कर सकते para
हैं; यह परिभाषित करने के लिए थोड़ा मुश्किल para
है foldr
, लेकिन यह निश्चित रूप से संभव है, और सभी को पता होना चाहिए कि यह कैसे किया जाता है!
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)
इसके para
साथ परिभाषित करने की चाल मूल डेटा की foldr
एक कॉपी को फिर से बनाना है, ताकि हम प्रत्येक चरण में पूंछ की प्रतिलिपि तक पहुंच प्राप्त कर सकें, भले ही हमारे पास मूल तक कोई पहुंच न हो। अंत में, snd
इनपुट की कॉपी को छोड़ देता है और सिर्फ आउटपुट वैल्यू देता है। यह बहुत कुशल नहीं है, लेकिन यदि आप सरासर अभिव्यक्ति में रुचि रखते हैं, तो आपको para
इससे अधिक नहीं मिलेगा foldr
। यदि आप के foldr
-encoded संस्करण का उपयोग करते हैं para
, तो safeTail
सब के बाद रैखिक समय लगेगा, तत्व द्वारा पूंछ तत्व की नकल करना।
तो, यह वह है: para
एक और अधिक सुविधाजनक संस्करण है, foldr
जो आपको सूची की पूंछ के साथ-साथ उससे गणना किए गए मूल्य तक तत्काल पहुंच प्रदान करता है।
सामान्य मामले में, एक फ़ाइटर के पुनरावर्ती निर्धारण के रूप में उत्पन्न डेटाटाइप के साथ काम करना
data Fix f = In (f (Fix f))
आपके पास
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)
और फिर से, दो परस्पर निश्चित हैं, उसी para
से परिभाषित के साथ cata
"एक प्रतिलिपि बनाएँ" चाल है
para psi = snd . cata (\ fxt -> (In (fmap fst fxt), psi fxt))
फिर से, para
कोई अधिक अभिव्यंजक नहीं है cata
, लेकिन यदि आप इनपुट के उपग्रहों तक आसान पहुंच चाहते हैं, तो अधिक सुविधाजनक है।
संपादित करें: मुझे एक और अच्छा उदाहरण याद आया।
बाइनरी खोज पेड़ों पर विचार करें Fix TreeF
जहां से दिया गया है
data TreeF sub = Leaf | Node sub Integer sub
और द्विआधारी खोज पेड़ों के लिए सम्मिलन को परिभाषित करने का प्रयास करें, पहले एक के रूप में cata
, फिर एक के रूप में para
। आप para
संस्करण को बहुत आसान पाएंगे , जैसा कि प्रत्येक नोड पर आपको एक सबट्री में सम्मिलित करने की आवश्यकता होगी, लेकिन दूसरे को उसी तरह संरक्षित करें जैसा वह था।
para f base xs = foldr (uncurry f) base $ zip xs (tail $tails xs)
, मेखिंक्स।