2013-04-17 7 views
14

यह हास्केल पुस्तकालयों के लिए अपने स्वयं के मोनाड उदाहरणों को परिभाषित करने के लिए एपीआई डिज़ाइन प्रथाओं से संबंधित एक प्रश्न है। डीएसएल के उदाहरण को अलग करने के लिए मोनाड उदाहरणों को परिभाषित करना एक अच्छा तरीका प्रतीत होता है। Par monad-par, hdph में monad; वितरित प्रक्रिया में Process; Eval समांतर आदि में ...जब (और जब नहीं) एक मोनाड को परिभाषित करने के लिए

मैं हैकेल पुस्तकालयों के दो उदाहरण लेता हूं, जिसका उद्देश्य डेटाबेस बैकएंड के साथ आईओओ है। मेरे द्वारा किए गए उदाहरण रीड आईओ के लिए riak और रेडिस आईओ के लिए hedis हैं।

हेडिस में, Redis मोनड is defined। वहाँ से, आप के रूप में redis साथ आईओ चलाएँ:

data Redis a -- instance Monad Redis 
runRedis :: Connection -> Redis a -> IO a 
class Monad m => MonadRedis m 
class MonadRedis m => RedisCtx m f | m -> f 
set :: RedisCtx m f => ByteString -> ByteString -> m (f Status) 

example = do 
    conn <- connect defaultConnectInfo 
    runRedis conn $ do 
    set "hello" "world" 
    world <- get "hello" 
    liftIO $ print world 

riak में, बातें अलग हैं:

create :: Client -> Int -> NominalDiffTime -> Int -> IO Pool 
ping :: Connection -> IO() 
withConnection :: Pool -> (Connection -> IO a) -> IO a 

example = do 
    conn <- connect defaultClient 
    ping conn 

runRedis के लिए दस्तावेज़ का कहना है: "runRedis से प्रत्येक कॉल कनेक्शन से एक नेटवर्क कनेक्शन लेता है पूल और दिया गया रेडिस एक्शन चलाता है। रन करने के लिए कॉल करें इस प्रकार ब्लॉक हो सकता है जबकि पूल से सभी कनेक्शन उपयोग में हैं। "। हालांकि, दंगा पैकेज भी कनेक्शन पूल लागू करता है। यह आईओ इकाई के शीर्ष पर अतिरिक्त इकाई उदाहरणों बिना किया जाता है:

create :: Client-> Int -> NominalDiffTime -> Int -> IO Pool 
withConnection :: Pool -> (Connection -> IO a) -> IO a 

exampleWithPool = do 
    pool <- create defaultClient 1 0.5 1 
    withConnection pool $ \conn -> ping conn 

तो, दो संकुल के बीच सादृश्य इन दोनों कार्यों के लिए नीचे फोड़े:

runRedis  :: Connection -> Redis a -> IO a 
withConnection :: Pool -> (Connection -> IO a) -> IO a 

जहां तक ​​मेरा बता सकते हैं, हेडीस पैकेज runRedis का उपयोग करके रेडिस के साथ आईओ क्रियाओं को समाहित करने के लिए एक मोनड Redis प्रस्तुत करता है। इसके विपरीत withConnection में दंगा पैकेज बस एक फ़ंक्शन लेता है जो Connection लेता है, और इसे आईओ मोनैड में निष्पादित करता है।

तो, अपने स्वयं के मोनाड उदाहरणों और मोनाड स्टैक को परिभाषित करने के लिए क्या प्रेरणाएं हैं? इस के दृष्टिकोण में दंगा और रेडिस पैकेज क्यों भिन्न हैं?

+6

उत्तर के संदर्भ के रूप में - यदि यह स्पष्ट नहीं है, तो 'रेडिस ए' और' कनेक्शन -> आईओ ए 'प्रकार लगभग बराबर हैं। तो यह अनिवार्य रूप से एक कॉस्मेटिक अंतर है, जो 'एनवी -> आईओ ए' बनाम 'रीडर टीएनवी आईओ ए' के ​​बराबर है। –

+0

तब इसका मतलब है कि शायद न तो सही है और 'कोडोडिटी आईओ कनेक्शन' वह मोनैड था जो वह सभी के साथ चाहता था। –

उत्तर

10

मेरे लिए यह भविष्य में कार्यान्वयन परिवर्तनों के विरुद्ध उपयोगकर्ताओं को encapsulation और संरक्षित करने के बारे में है। जैसा केसी ने इंगित किया है, ये दोनों मोटे तौर पर बराबर हैं - मूल रूप से Reader Connection मोनैड। लेकिन कल्पना करें कि सड़क के नीचे अनिश्चित परिवर्तनों के अधीन ये कैसे व्यवहार करेंगे। क्या होगा यदि दोनों पैकेज निर्णय लेते हैं कि उपयोगकर्ता को पाठक के बजाय राज्य मोनैड इंटरफेस की आवश्यकता है? अगर ऐसा होता है, riak के withConnection समारोह इस तरह एक प्रकार हस्ताक्षर करने के लिए बदल जाएगा:

withConnection :: Pool -> (Connection -> IO (a, Connection)) -> IO a 

इस उपयोगकर्ता कोड में आमूलचूल परिवर्तन की आवश्यकता होगी। लेकिन रेडिस पैकेज अपने उपयोगकर्ताओं को तोड़ने के बिना इस तरह के बदलाव को खींच सकता है।

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

जब इस तरह से कहा गया, तो कुछ निष्कर्ष निकाल सकते हैं कि अपने स्वयं के मोनड को परिभाषित करना बेहतर दृष्टिकोण है। लेकिन मुझे नहीं लगता कि यह हमेशा मामला है। (lens लाइब्रेरी एक संभावित अच्छे काउंटर उदाहरण के रूप में दिमाग में आती है।) एक नए मोनड को परिभाषित करने की लागत है। यदि आप मोनैड ट्रांसफार्मर का उपयोग कर रहे हैं, तो यह एक प्रदर्शन जुर्माना लगा सकता है।अन्य मामलों में एपीआई अधिक वर्बोज़ होने का अंत हो सकता है। हास्केल बहुत अच्छा है कि आप सिंटैक्स को बहुत कम रखें और इस विशेष मामले में, अंतर बहुत बड़ा नहीं है - शायद कुछ liftIO रेडिस के लिए और दंगा के लिए कुछ भेड़ के बच्चे हैं।

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

1

इस मामले में मुझे लगता है कि मोनाड लागू करना एक गलती थी। यह अजीब जावा डेवलपर्स सिर्फ उन्हें रखने के लिए सभी प्रकार के डिज़ाइन पैटर्न को कार्यान्वित कर रहा है।

उदाहरण के लिए एचडीबीसी सादा आईओ मोनैड में भी काम करता है।

रेडिस लाइब्रेरी के लिए मोनाड कुछ भी उपयोगी नहीं लाता है। एकमात्र चीज जो इसे प्राप्त करती है वह एक फ़ंक्शन तर्क (कनेक्शन) से छुटकारा पाने के लिए है। लेकिन आप रेडिस मोनड के अंदर हर आईओ ऑपरेशन को उठाने के लिए भुगतान करते हैं।

इसके अलावा अगर आप कभी भी अब आप यह पता लगाने की जो संचालन लिफ्ट करने के लिए जहां :)

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

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