2012-03-09 12 views
17

मैं हस्केल में गणना कैसे मॉडलिंग के बारे में दिलचस्पी लेता हूं। कई संसाधनों ने मोनैड को "संगत गणना" और तीरों को "गणना के सार दृश्य" के रूप में वर्णित किया है। मैंने इस तरह से वर्णित मोनोइड्स, मकान या आवेदक फंक्शंस कभी नहीं देखा है। ऐसा लगता है कि उनमें आवश्यक संरचना की कमी है।गणना निर्माण (मोनाड्स, तीर, इत्यादि)

मुझे यह विचार दिलचस्प लगता है और आश्चर्य होता है कि क्या कोई अन्य संरचनाएं हैं जो कुछ समान करती हैं। यदि हां, तो कुछ संसाधन क्या हैं जिनका उपयोग मैं अपने साथ परिचित करने के लिए कर सकता हूं? क्या हैकेज पर कोई पैकेज है जो आसानी से आ सकता है?

नोट: यह सवाल Monads vs. Arrows और https://stackoverflow.com/questions/2395715/resources-for-learning-monads-functors-monoids-arrows-etc के समान है, लेकिन मैं funtors परे निर्माणों, अनुप्रयोगी functors, monads, और तीर के लिए देख रहा हूँ।

संपादित करें: मैं स्वीकार करता हूं कि आवेदक फंक्चरर्स को "कम्प्यूटेशनल संरचना" माना जाना चाहिए, लेकिन मैं वास्तव में कुछ ऐसा ढूंढ रहा हूं जो मैं अभी तक नहीं आया हूं। इसमें आवेदक फैनक्टर, मोनैड और तीर शामिल हैं।

+0

मोनाड बनाम तीर पेज एक ऐसे पेपर से लिंक करता है जो आवेदक फैनक्टर (उर्फ मुहावरे) की तुलना करता है। –

+0

आवेदक फंक्शंस सबसे निश्चित रूप से * composable गणना पर अच्छा * हैं! वास्तव में, वे मोनैड्स से बेहतर लिखते हैं (दो आवेदक फंक्शंस की संरचना एक आवेदक मज़ेदार है, जो मोनैड के लिए नहीं है)। – ehird

उत्तर

23

Arrows श्रेणियों द्वारा सामान्यीकृत किया जाता है, और Category टाइपक्लास द्वारा।

class Category f where 
    (.) :: f a b -> f b c -> f a c 
    id :: f a a 

Arrow typeclass परिभाषा Category एक सुपर क्लास के रूप में है। श्रेणियां (हैकेल भावना में) कार्यों को सामान्यीकृत करें (आप उन्हें लिख सकते हैं लेकिन उन्हें लागू नहीं कर सकते हैं) और इसलिए निश्चित रूप से "गणना का मॉडल" है। Arrow tuples के साथ काम करने के लिए अतिरिक्त संरचना के साथ Category प्रदान करता है। इसलिए, Category हास्केल की फ़ंक्शन स्पेस के बारे में कुछ दर्पण करता है, Arrow उत्पाद प्रकारों के बारे में कुछ बताता है।

प्रत्येक Monad "क्लेस्ली श्रेणी" नामक किसी चीज़ को जन्म देता है और यह निर्माण आपको ArrowApply के उदाहरण देता है। आप किसी भी ArrowApply से बाहर बना सकते हैं जैसे कि पूर्ण सर्कल जा रहा है, आपका व्यवहार नहीं बदलता है, इसलिए कुछ गहरी समझ में Monad और ArrowApply समान हैं।

newtype Kleisli m a b = Kleisli { runKleisli :: a -> m b } 

instance Monad m => Category (Kleisli m) where 
    id = Kleisli return 
    (Kleisli f) . (Kleisli g) = Kleisli (\b -> g b >>= f) 

instance Monad m => Arrow (Kleisli m) where 
    arr f = Kleisli (return . f) 
    first (Kleisli f) = Kleisli (\ ~(b,d) -> f b >>= \c -> return (c,d)) 
    second (Kleisli f) = Kleisli (\ ~(d,b) -> f b >>= \c -> return (d,c)) 

असल में हर Arrow एक ApplicativeCategory सुपर क्लास के अलावा (सार्वभौमिक प्रकार सही पाने के लिए मात्रा निर्धारित) को जन्म देता है, और मेरा मानना ​​है कि उचित Category और Applicative के संयोजन अपने Arrow को फिर से संगठित करने के लिए पर्याप्त है।

तो, ये संरचनाएं गहराई से जुड़ी हुई हैं।

चेतावनी: की इच्छा-धोनी टिप्पणी। सोच के Functor/Applicative/Monad तरह से और सोच के Category/Arrow रास्ता के बीच एक केंद्रीय अंतर यह है कि जबकि Functor और उसके जैसे लोग वस्तु (हास्केल में प्रकार) के स्तर पर सामान्यीकरण, कर रहे हैं Category/Arrow की generelazation हैं morphism (हास्केल में कार्य) की धारणा। मेरा विश्वास यह है कि सामान्यीकृत morphism के स्तर पर सोच सामान्यीकृत ऑब्जेक्ट्स के स्तर पर सोचने से उच्च स्तर का अबास्ट्रक्शन शामिल है। कभी-कभी यह अच्छी बात है, दूसरी बार यह नहीं है। दूसरी ओर, इस तथ्य के बावजूद कि Arrows का एक विशिष्ट आधार है, और गणित में कोई भी Applicative दिलचस्प नहीं लगता है, यह मेरी समझ है कि Applicative आमतौर पर Arrow से बेहतर समझा जाता है।

असल में आप सोच सकते हैं "श्रेणी < तीर < ArrowApply" और "functor < अनुप्रयोगी < इकाई" ऐसी है कि "श्रेणी ~ functor", "तीर ~ अनुप्रयोगी" और "ArrowApply ~ इकाई"।

अधिक नीचे कंक्रीट: एक बार "तीर" की दिशा पलट सकता है "दोहरे" या "सह-निर्माण पाने के लिए स्पष्ट निर्माण में (सिर्फ यहाँ morphisms अर्थ): अन्य संरचनाओं अभिकलन मॉडल करने के लिए के रूप में "। तो, अगर एक इकाई

class Functor m => Monad m where 
    return :: a -> m a 
    join :: m (m a) -> m a 

के रूप में परिभाषित किया गया है (ठीक है, मुझे पता है कि कैसे हास्केल चीजों को परिभाषित करता है नहीं है, लेकिन ma >>= f = join $ fmap f ma और join x = x >>= id तो यह बस के रूप में अच्छी तरह से हो सकता है) तो comonad

class Functor m => Comonad m where 
    extract :: m a -> a -- this is co-return 
    duplicate :: m a -> m (m a) -- this is co-join 
है

यह बात भी काफी आम है। यह पता चला है कि Comonadसेलुलर ऑटोमाटा की बुनियादी अंतर्निहित संरचना है। completness के लिए, मैं कहना चाहिए कि एडवर्ड Kmett के Control.Comonad पुट duplicate functor और Comonad "बढ़ाई functors के लिए" के बीच एक कक्षा में है क्योंकि आप भी परिभाषित कर सकते हैं

extend :: (m a -> b) -> m a -> m b -- Looks familiar? this is just the dual of >>= 
    extend f = fmap f . duplicate 
    --this is enough 
    duplicate = extend id 

ऐसा लगता है कि सब Monad रों भी "बढ़ाई"

हैं
monadDuplicate :: Monad m => m a -> m (m a) 
    monadDuplicate = return 

जबकि सभी Comonads "joinable" हैं

comonadJoin :: Comonad m => m (m a) -> m a 
    comonadJoin = extract 
तो

ये संरचनाएं एक साथ बहुत करीब हैं।

+0

ग्रेट, श्रेणियां और कॉमोनैड मेरे अगले दो विषय हैं। धन्यवाद। –

+0

आह मैं आपको सेलुलर ऑटोमाटा उदाहरण से प्यार करता हूँ। एडवर्ड Kmett में हर कॉमोनड को हास्केल में एक मोनड में बनाने के बारे में वास्तव में एक अच्छी पोस्ट है, लेकिन दूसरी तरफ नहीं। [लिंक] (http://comonad.com/reader/2011/monads-from-comonads/)। यह बहुत उच्च स्तर की सामग्री है, लेकिन यदि आप समय लेते हैं तो यह आपको दोनों के बीच कनेक्शन को समझ देगा। –

+1

@EdgarKlerks कि पोस्ट मुझे लगता है कि के परिणामों में से एक सबसे दिलचस्प यह है कि 'Store' comonad बल्कि मौलिक हो सकता है: के बाद से लेंस बस" दुकान comonad के सह बीजगणित "हैं (उर्फ' लेंस अब एक = -> स्टोर बीए) 'और 'स्टेट' स्टोर स्टोर कॉमोनैड का अंत ले कर आपको मिलता है। लेंस और राज्य के बीच आप कुछ जरूरी प्रोग्रामिंग की तरह एक बहुत कुछ है। मैं अभी भी इस हालांकि के महत्व को समझने से aways लग रहा है। –

8

सभी मोनाड्स तीर हैं (मोनाड एरोमोर्फिक के लिए आइसोमोर्फिक है)। एक अलग तरीके से, सभी मोनाड्स Applicative के उदाहरण हैं, जहां <*>Control.Monad.ap और *>>> है। आवेदक कमजोर है क्योंकि यह >>= ऑपरेशन की गारंटी नहीं देता है। इस प्रकार आवेदक उन गणनाओं को कैप्चर करता है जो पिछले परिणामों और मूल्यों पर शाखा की जांच नहीं करते हैं। पूर्वदर्शी में बहुत मोनैडिक कोड वास्तव में आवेदक है, और एक साफ पुनर्लेख के साथ ऐसा होगा।

जीएनसी 7.4.1 में हालिया प्रतिबंध प्रकारों के साथ मोनैड का विस्तार, अब restricted monads के लिए अच्छे डिजाइन हो सकते हैं। और parameterized monads पर भी लोग देख रहे हैं, और निश्चित रूप से मैं Oleg द्वारा कुछ के लिए एक लिंक शामिल करता हूं।

+0

हां, मोनैड (मोटे तौर पर) तीरों का विशेषज्ञता और आवेदकों का एक सामान्यीकरण हैं। क्या मोनैड के कोई सामान्यीकरण हैं जो तीर नहीं हैं? शायद कुछ ऐसा जो तीर को सामान्य करता है? –

4

पुस्तकालयों में ये संरचनाएं विभिन्न प्रकार की गणनाओं को जन्म देती हैं।

उदाहरण के लिए आवेदकों का उपयोग स्थिर प्रभावों को लागू करने के लिए किया जा सकता है। इसके साथ मेरा मतलब प्रभाव है, जो फोरहैंड में परिभाषित हैं। उदाहरण के लिए, एक राज्य मशीन को कार्यान्वित करते समय, एक इनपुट स्थिति को अस्वीकार या स्वीकार करते हैं। उनका उपयोग उनके इनपुट के संदर्भ में अपनी आंतरिक संरचना में हेरफेर करने के लिए नहीं किया जा सकता है।

प्रकार यह कहता है कि सब:

<*> :: f (a -> b) -> f a -> f b 

यह कारण करने के लिए आसान है, च की संरचना एक के इनपुट नहीं निर्भर किया जा सकता है ओम। क्योंकि कोई प्रकार के स्तर पर एफ तक नहीं पहुंच सकता है।

गतिशील प्रभावों के लिए मोनाड्स का उपयोग किया जा सकता है। इसे टाइप हस्ताक्षर से भी तर्क दिया जा सकता है:

>>= :: m a -> (a -> m b) -> m b 

आप इसे कैसे देख सकते हैं? क्योंकि एम के समान "स्तर" पर है। गणितीय रूप से यह एक दो चरण की प्रक्रिया है। बाइंड दो फ़ंक्शन की एक रचना है: fmap और शामिल हों। पहले हम एक नई संरचना वर्ष एक में एम्बेडेड बनाने के लिए monadic कार्रवाई के साथ FMAP एक साथ उपयोग करें:

fmap :: (a -> b) -> m a -> m b 
f :: (a -> m b) 
m :: m a 
fmap f :: m a -> m (m b) 
fmap f m :: m (m b) 

FMAP इनपुट मूल्य के आधार पर, एक नई संरचना बना सकते हैं। फिर हम में शामिल होने के साथ संरचना पतन, इस प्रकार हम एक तरह से monadic गणना कि इनपुट पर निर्भर करता है के भीतर से संरचना में हेरफेर करने में सक्षम हैं:

join :: m (m a) -> m a 
join (fmap f m) :: m b 

कई monads साथ लागू करने के लिए आसान कर रहे हैं में शामिल होने:

(>>=) = join . fmap 

यह monads के साथ संभव है:

addCounter :: Int -> m Int() 

लेकिन applicatives साथ नहीं है, लेकिन applicatives (और किसी भी इकाई) की तरह कर सकते हैं:

addOne :: m Int() 

तीर इनपुट और आउटपुट प्रकारों पर अधिक नियंत्रण देते हैं, लेकिन मेरे लिए वे वास्तव में आवेदकों के समान महसूस करते हैं। शायद मैं इसके बारे में गलत हूँ।

संबंधित मुद्दे