एफ-अलजेब्रा और एफ-कोलजेब्रस गणितीय संरचनाएं हैं जो प्रेरक प्रकार (या पुनरावर्ती प्रकार ) के बारे में तर्क में सहायक हैं ।
एफ अल्जेब्रास
हम सबसे पहले 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
।
निष्कर्ष
तो, संक्षेप में, एफ-अल्जेब्रस सिलवटों को परिभाषित करने की अनुमति देता है, अर्थात्, संचालन जो एक एकल मूल्य में पुनरावर्ती संरचना को कम करते हैं, और एफ-कोलजेब्रस इसके विपरीत करने की अनुमति देते हैं: एक एकल मूल्य से [संभावित] अनंत संरचना का निर्माण।
वास्तव में हास्केल एफ-अलजेब्रा और एफ-कोलजेब्रस में मेल खाता है। यह एक बहुत अच्छी संपत्ति है जो प्रत्येक प्रकार में 'नीचे' मूल्य की उपस्थिति का परिणाम है। तो हास्केल में, दोनों पुनरावर्ती प्रकार के लिए सिलवटों और अनफॉल्ड को बनाया जा सकता है। हालांकि, इसके पीछे सैद्धांतिक मॉडल जो मैंने ऊपर प्रस्तुत किया है, उससे अधिक जटिल है, इसलिए मैंने जानबूझकर इसे टाला है।
उम्मीद है की यह मदद करेगा।