एफ-अलजेब्रा और एफ-कोलजेब्रस गणितीय संरचनाएं हैं जो प्रेरक प्रकार (या पुनरावर्ती प्रकार ) के बारे में तर्क में सहायक हैं ।
एफ अल्जेब्रास
हम सबसे पहले F-algebras से शुरुआत करेंगे। मैं यथासंभव सरल होने की कोशिश करूंगा।
मुझे लगता है कि आप जानते हैं कि एक पुनरावर्ती प्रकार क्या है। उदाहरण के लिए, यह पूर्णांकों की सूची के लिए एक प्रकार है:
data IntList = Nil | Cons (Int, IntList)
यह स्पष्ट है कि यह पुनरावर्ती है - वास्तव में, इसकी परिभाषा स्वयं को संदर्भित करती है। इसकी परिभाषा में दो डेटा निर्माता हैं, जिनके निम्न प्रकार हैं:
Nil :: () -> IntList
Cons :: (Int, IntList) -> IntList
ध्यान दें कि मैं के प्रकार लिखा है Nilके रूप में () -> IntList, बस नहीं IntList। ये वास्तव में सैद्धांतिक दृष्टिकोण से समकक्ष प्रकार हैं, क्योंकि ()प्रकार में केवल एक निवासी है।
यदि हम इन कार्यों के हस्ताक्षर अधिक सेट-थ्योरिटिकल तरीके से लिखते हैं, तो हम प्राप्त करेंगे
Nil :: 1 -> IntList
Cons :: Int × IntList -> IntList
जहां 1एक इकाई सेट (एक तत्व के साथ सेट) और A × Bऑपरेशन दो सेटों का एक क्रॉस उत्पाद है ( Aऔर B, उन युग्मों का सेट (a, b)जहां aसभी तत्वों के माध्यम से जाता है Aऔर bसभी तत्वों के माध्यम से जाता है B)।
दो सेटों का मिलन समाप्त करें Aऔर Bएक सेट है A | Bजो सेटों का एक संघ है {(a, 1) : a in A}और {(b, 2) : b in B}। अनिवार्य रूप से यह दोनों Aऔर से सभी तत्वों का एक सेट है B, लेकिन इस तत्व में से प्रत्येक के साथ Aया तो संबंधित 'चिह्नित' है B, इसलिए जब हम किसी भी तत्व को चुनते हैं, तो A | Bहम तुरंत यह जान लेंगे कि यह तत्व आया था Aया उससे B।
हम 'जॉइन' कर सकते हैं Nilऔर Consकार्य कर सकते हैं , इसलिए वे एक सेट पर काम करने वाले एकल फंक्शन का निर्माण करेंगे 1 | (Int × IntList):
Nil|Cons :: 1 | (Int × IntList) -> IntList
वास्तव में, यदि Nil|Consफ़ंक्शन को ()मूल्य पर लागू किया जाता है (जो, जाहिर है, 1 | (Int × IntList)सेट करने के लिए है), तो यह व्यवहार करता है जैसे कि यह था Nil; यदि Nil|Consकिसी भी प्रकार के मूल्य पर लागू किया जाता है (Int, IntList)(ऐसे मूल्य सेट में भी हैं 1 | (Int × IntList), तो यह व्यवहार करता है Cons।
अब एक और डेटाटाइप पर विचार करें:
data IntTree = Leaf Int | Branch (IntTree, IntTree)
इसके निम्न निर्माता हैं:
Leaf :: Int -> IntTree
Branch :: (IntTree, IntTree) -> IntTree
जो भी एक समारोह में शामिल हो सकते हैं:
Leaf|Branch :: Int | (IntTree × IntTree) -> IntTree
यह देखा जा सकता है कि इस joinedकार्य के दोनों प्रकार समान हैं: वे दोनों समान दिखते हैं
f :: F T -> T
जहाँ Fएक प्रकार का परिवर्तन होता है जो हमारे प्रकार को लेता है और अधिक जटिल प्रकार देता है, जिसमें xऔर |संचालन, उपयोग Tऔर संभवतः अन्य प्रकार होते हैं। उदाहरण के लिए, निम्नानुसार IntListऔर IntTree Fदिखता है:
F1 T = 1 | (Int × T)
F2 T = Int | (T × T)
हम तुरंत नोटिस कर सकते हैं कि किसी भी बीजीय प्रकार को इस तरह से लिखा जा सकता है। वास्तव में, इसीलिए उन्हें 'बीजगणितीय' कहा जाता है: वे कई प्रकार के 'सम्स' (यूनियनों) और 'उत्पादों' (क्रॉस उत्पादों) से मिलकर बनते हैं।
अब हम एफ-बीजगणित को परिभाषित कर सकते हैं। एफ-बीजगणित सिर्फ एक जोड़ी है (T, f), जहां Tकुछ प्रकार है और प्रकार fका एक कार्य है f :: F T -> T। हमारे उदाहरणों में F-algebras हैं (IntList, Nil|Cons)और (IntTree, Leaf|Branch)। ध्यान दें, हालांकि, इसके बावजूद कि fप्रत्येक एफ के लिए उस प्रकार का फ़ंक्शन समान है, Tऔर fस्वयं मनमाना हो सकता है। उदाहरण के लिए, (String, g :: 1 | (Int x String) -> String)या (Double, h :: Int | (Double, Double) -> Double)कुछ के लिए gऔर hइसी एफ के लिए एफ-अल्जेब्रा भी हैं।
बाद में हम एफ-बीजगणित समरूपता और फिर प्रारंभिक एफ-बीजगणित का परिचय दे सकते हैं , जिसमें बहुत उपयोगी गुण हैं। वास्तव में, (IntList, Nil|Cons)एक प्रारंभिक F1-बीजगणित है, और (IntTree, Leaf|Branch)एक प्रारंभिक F2-बीजगणित है। मैं इन शर्तों और गुणों की सटीक परिभाषा प्रस्तुत नहीं करूंगा क्योंकि वे जरूरत से ज्यादा जटिल और सार हैं।
बहरहाल, तथ्य यह है कि, कहते हैं, (IntList, Nil|Cons)एफ-बीजगणित हमें foldइस प्रकार पर परिभाषित -समान फ़ंक्शन की अनुमति देता है । जैसा कि आप जानते हैं, गुना एक प्रकार का ऑपरेशन है जो एक परिमित मूल्य में कुछ पुनरावर्ती डेटाटाइप को बदलता है। उदाहरण के लिए, हम पूर्णांक की एक सूची को एक एकल मान में बदल सकते हैं जो सूची में सभी तत्वों का योग है:
foldr (+) 0 [1, 2, 3, 4] -> 1 + 2 + 3 + 4 = 10
किसी भी पुनरावर्ती डेटाटाइप पर इस तरह के ऑपरेशन को सामान्य करना संभव है।
निम्नलिखित foldrसमारोह का एक हस्ताक्षर है :
foldr :: ((a -> b -> b), b) -> [a] -> b
ध्यान दें कि मैंने पहले दो तर्कों को पिछले एक से अलग करने के लिए ब्रेसिज़ का उपयोग किया है। यह वास्तविक foldrकार्य नहीं है, लेकिन यह इसके लिए आइसोमोर्फिक है (अर्थात, आप आसानी से दूसरे से एक और इसके विपरीत प्राप्त कर सकते हैं)। आंशिक रूप से लागू foldrनिम्नलिखित हस्ताक्षर होंगे:
foldr ((+), 0) :: [Int] -> Int
हम देख सकते हैं कि यह एक फ़ंक्शन है जो पूर्णांक की एक सूची लेता है और एक पूर्णांक देता है। आइए ऐसे फ़ंक्शन को हमारे IntListप्रकार के संदर्भ में परिभाषित करें।
sumFold :: IntList -> Int
sumFold Nil = 0
sumFold (Cons x xs) = x + sumFold xs
हम देखते हैं कि इस फ़ंक्शन में दो भाग होते हैं: पहला भाग इस फ़ंक्शन के Nilभाग के व्यवहार को IntListपरिभाषित करता है, और दूसरा भाग कार्य के व्यवहार को परिभाषित करता है Cons।
अब मान लीजिए कि हम हास्केल में नहीं बल्कि कुछ भाषा में प्रोग्रामिंग कर रहे हैं जो सीधे प्रकार के हस्ताक्षरों में बीजगणितीय प्रकारों के उपयोग की अनुमति देता है (अच्छी तरह से, तकनीकी रूप से हास्केल टुपल्स और Either a bडेटाटाइप के माध्यम से बीजगणितीय प्रकारों के उपयोग की अनुमति देता है , लेकिन इससे अनावश्यक क्रियात्मकता हो जाएगी)। एक समारोह पर विचार करें:
reductor :: () | (Int × Int) -> Int
reductor () = 0
reductor (x, s) = x + s
यह देखा जा सकता है कि एफ-बीजगणित की परिभाषा के अनुसार, reductorफ़ंक्शन का एक प्रकार F1 Int -> Intहै! दरअसल, यह जोड़ी (Int, reductor)F1-बीजगणित है।
क्योंकि IntListएक प्रारंभिक एफ 1-बीजगणित है, प्रत्येक प्रकार के लिए Tऔर प्रत्येक फ़ंक्शन के लिए एक फ़ंक्शन r :: F1 T -> Tमौजूद है, जिसे कैटोर्फिज्म कहा जाता है r, जिसके लिए अभिसरण होता IntListहै T, और ऐसा फ़ंक्शन अद्वितीय होता है। वास्तव में, हमारे उदाहरण में इसके लिए एक कायापलट reductorहै sumFold। ध्यान दें कि कैसे reductorऔर sumFoldसमान हैं: उनके पास लगभग समान संरचना है! में reductorपरिभाषा sपैरामीटर उपयोग (प्रकार जिनमें से से मेल खाती है Tकी गणना के परिणाम के उपयोग से मेल खाती है) sumFold xsमें sumFoldपरिभाषा।
बस इसे और अधिक स्पष्ट करने और पैटर्न को देखने में आपकी मदद करने के लिए, यहां एक और उदाहरण है, और हम फिर से परिणामी तह फ़ंक्शन से शुरू करते हैं। उस appendफ़ंक्शन पर विचार करें जो अपना पहला तर्क दूसरे के लिए देता है:
(append [4, 5, 6]) [1, 2, 3] = (foldr (:) [4, 5, 6]) [1, 2, 3] -> [1, 2, 3, 4, 5, 6]
यह हमारे पर कैसा दिखता है IntList:
appendFold :: IntList -> IntList -> IntList
appendFold ys () = ys
appendFold ys (Cons x xs) = x : appendFold ys xs
फिर से, चलिए लिखने की कोशिश करते हैं:
appendReductor :: IntList -> () | (Int × IntList) -> IntList
appendReductor ys () = ys
appendReductor ys (x, rs) = x : rs
appendFoldएक प्रलयवाद है appendReductorजिसके लिए रूपांतरित IntListहोता है IntList।
तो, अनिवार्य रूप से, एफ-अल्जेब्रा हमें पुनरावर्ती डेटास्ट्रक्चर पर 'सिलवटों' को परिभाषित करने की अनुमति देते हैं, अर्थात्, ऐसे ऑपरेशन जो हमारी संरचनाओं को कुछ मूल्य तक कम करते हैं।
एफ coalgebras
एफ-कोलजेब्रस को एफ-अल्जेब्रा के लिए 'दोहरी' शब्द कहा जाता है। वे हमें unfoldsपुनरावर्ती डेटाटिप्स के लिए परिभाषित करने की अनुमति देते हैं , अर्थात्, कुछ मूल्य से पुनरावर्ती संरचनाओं के निर्माण का तरीका।
मान लें कि आपके पास निम्न प्रकार हैं:
data IntStream = Cons (Int, IntStream)
यह पूर्णांकों की एक अनंत धारा है। इसके एकमात्र निर्माता में निम्न प्रकार हैं:
Cons :: (Int, IntStream) -> IntStream
या, सेट के संदर्भ में
Cons :: Int × IntStream -> IntStream
हास्केल आपको डेटा कंस्ट्रक्टर्स पर मिलान करने की अनुमति देता है, इसलिए आप निम्नलिखित कार्य परिभाषित कर सकते हैं IntStream:
head :: IntStream -> Int
head (Cons (x, xs)) = x
tail :: IntStream -> IntStream
tail (Cons (x, xs)) = xs
आप इन कार्यों को प्रकार के एकल कार्य में स्वाभाविक रूप से शामिल कर सकते हैं IntStream -> Int × IntStream:
head&tail :: IntStream -> Int × IntStream
head&tail (Cons (x, xs)) = (x, xs)
ध्यान दें कि फ़ंक्शन का परिणाम हमारे IntStreamप्रकार के बीजगणितीय प्रतिनिधित्व के साथ कैसे मेल खाता है । इसी तरह की बात अन्य पुनरावर्ती डेटा प्रकारों के लिए भी की जा सकती है। हो सकता है कि आपने पहले ही पैटर्न पर ध्यान दिया हो। मैं प्रकार के कार्यों के एक परिवार की बात कर रहा हूँ
g :: T -> F T
जहां Tकुछ प्रकार है। अब से हम परिभाषित करेंगे
F1 T = Int × T
अब, एफ-कोलजेब्रा एक जोड़ी है (T, g), जहां Tएक प्रकार है और प्रकार gका एक कार्य है g :: T -> F T। उदाहरण के लिए, (IntStream, head&tail)एफ 1-कोलजेब्रा है। फिर से, जैसे कि एफ-अल्जेब्रा में, gऔर Tमनमाना हो सकता है, उदाहरण के लिए, (String, h :: String -> Int x String)कुछ एच के लिए एफ 1-कोलजेब्रा भी है।
सभी F-Coalgebras के बीच तथाकथित टर्मिनल F-Coalgebras हैं , जो प्रारंभिक F-algebras से दोहरे हैं। उदाहरण के लिए, IntStreamएक टर्मिनल F-Coalgebra है। इसका मतलब यह है कि प्रत्येक प्रकार के लिए Tऔर प्रत्येक फ़ंक्शन के लिए p :: T -> F1 Tएक फ़ंक्शन मौजूद है, जिसे एनामॉर्फिज़्म कहा जाता है , जो कि परिवर्तित Tहोता है IntStream, और ऐसा फ़ंक्शन अद्वितीय है।
निम्नलिखित फ़ंक्शन पर विचार करें, जो दिए गए एक से शुरू होने वाले पूर्णांक की एक धारा उत्पन्न करता है:
nats :: Int -> IntStream
nats n = Cons (n, nats (n+1))
अब एक फ़ंक्शन का निरीक्षण करते हैं natsBuilder :: Int -> F1 Int, जो है natsBuilder :: Int -> Int × Int:
natsBuilder :: Int -> Int × Int
natsBuilder n = (n, n+1)
फिर से, हम natsऔर के बीच कुछ समानता देख सकते हैं natsBuilder। यह उस कनेक्शन से बहुत मिलता-जुलता है जिसे हमने पहले रिडक्टर्स और सिलवटों के साथ देखा है। natsके लिए anamorphism है natsBuilder।
एक अन्य उदाहरण, एक फ़ंक्शन जो एक मान और एक फ़ंक्शन लेता है और फ़ंक्शन के क्रमिक अनुप्रयोगों की एक धारा को मान में लौटाता है:
iterate :: (Int -> Int) -> Int -> IntStream
iterate f n = Cons (n, iterate f (f n))
इसका बिल्डर फ़ंक्शन निम्नलिखित है:
iterateBuilder :: (Int -> Int) -> Int -> Int × Int
iterateBuilder f n = (n, f n)
तब के iterateलिए एक anamorphism है iterateBuilder।
निष्कर्ष
तो, संक्षेप में, एफ-अल्जेब्रस सिलवटों को परिभाषित करने की अनुमति देता है, अर्थात्, संचालन जो एक एकल मूल्य में पुनरावर्ती संरचना को कम करते हैं, और एफ-कोलजेब्रस इसके विपरीत करने की अनुमति देते हैं: एक एकल मूल्य से [संभावित] अनंत संरचना का निर्माण।
वास्तव में हास्केल एफ-अलजेब्रा और एफ-कोलजेब्रस में मेल खाता है। यह एक बहुत अच्छी संपत्ति है जो प्रत्येक प्रकार में 'नीचे' मूल्य की उपस्थिति का परिणाम है। तो हास्केल में, दोनों पुनरावर्ती प्रकार के लिए सिलवटों और अनफॉल्ड को बनाया जा सकता है। हालांकि, इसके पीछे सैद्धांतिक मॉडल जो मैंने ऊपर प्रस्तुत किया है, उससे अधिक जटिल है, इसलिए मैंने जानबूझकर इसे टाला है।
उम्मीद है की यह मदद करेगा।