हाँ, वह है 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), मेखिंक्स।