मैं इस समस्या के समाधान पर काम कर रहा हूं।
ए) एक शुद्ध और एकल पिरोया विनिर्देश
बी) एकल पिरोया विनिर्देश StateT
का उपयोग करता है आम राज्य साझा करने के लिए
में अपने सभी समवर्ती कोड शुद्ध: उच्च-स्तरीय सारांश यह है कि आप है समग्र वास्तुकला मॉडल-व्यू-नियंत्रक द्वारा प्रेरित है। आपके पास:
- नियंत्रकों, जो effectful आदानों
- दृश्य है, जो effectful outputs हैं
- एक मॉडल है, जो एक शुद्ध धारा परिवर्तन
मॉडल केवल एक नियंत्रक के साथ बातचीत कर सकते हैं कर रहे हैं और एक दृश्य। हालांकि, दोनों नियंत्रक और विचार मोनोइड्स हैं, इसलिए आप एकाधिक नियंत्रकों को एकल नियंत्रक और एकाधिक दृश्यों को एक ही दृश्य में जोड़ सकते हैं। रेखचित्र, यह इस तरह दिखता है:
controller1 - -> view1
\ /
controller2 ---> controllerTotal -> model -> viewTotal---> view2
/ \
controller3 - -> view3
\______ ______/ \__ __/ \___ ___/
v v v
Effectful Pure Effectful
मॉडल एक शुद्ध, एकल पिरोया धारा ट्रांसफार्मर कि Arrow
और ArrowChoice
लागू करता है। , मैं धक्का-आधारित pipes
का उपयोग
Arrow
समानांतरवाद
ArrowChoice
को एकल पिरोया बराबर है संगामिति
इस मामले में करने के लिए एकल पिरोया बराबर है,: कारण है कि वह यह है कि जो एक सही Arrow
और ArrowChoice
उदाहरण प्रतीत होता है, हालांकि मैं अभी भी कानूनों की पुष्टि करने पर काम कर रहा हूं, इसलिए यह समाधान तब भी प्रयोगात्मक है जब तक कि मैं अपने सबूत पूरा नहीं कर लेता। जो उत्सुक हैं, उनके लिए प्रासंगिक प्रकार और उदाहरण हैं:
newtype Edge m r a b = Edge { unEdge :: a -> Pipe a b m r }
instance (Monad m) => Category (Edge m r) where
id = Edge push
(Edge p2) . (Edge p1) = Edge (p1 >~> p2)
instance (Monad m) => Arrow (Edge m r) where
arr f = Edge (push />/ respond . f)
first (Edge p) = Edge $ \(b, d) ->
evalStateP d $ (up \>\ unsafeHoist lift . p />/ dn) b
where
up() = do
(b, d) <- request()
lift $ put d
return b
dn c = do
d <- lift get
respond (c, d)
instance (Monad m) => ArrowChoice (Edge m r) where
left (Edge k) = Edge (bef >=> (up \>\ (k />/ dn)))
where
bef x = case x of
Left b -> return b
Right d -> do
_ <- respond (Right d)
x2 <- request()
bef x2
up() = do
x <- request()
bef x
dn c = respond (Left c)
मॉडल को एक मोनड ट्रांसफार्मर भी होना चाहिए। कारण यह है कि हम साझा स्थिति का ट्रैक रखने के लिए बेस मोनैड में StateT
एम्बेड करना चाहते हैं। इस मामले में, pipes
बिल फिट बैठता है।
पहेली का अंतिम भाग जटिल परिसर प्रणाली लेने और इसे शुद्ध एकल-थ्रेडेड समकक्ष में वितरित करने का एक परिष्कृत वास्तविक-दुनिया उदाहरण है। इसके लिए मैं अपने आने वाले rcpl
लाइब्रेरी का उपयोग करता हूं ("पठन-समवर्ती-प्रिंट-लूप" के लिए छोटा)। rcpl
लाइब्रेरी का उद्देश्य कंसोल पर एक समवर्ती इंटरफ़ेस प्रदान करना है जो आपको कंसोल पर एक साथ प्रिंट करते समय उपयोगकर्ता से इनपुट पढ़ने देता है, लेकिन मुद्रित आउटपुट के बिना उपयोगकर्ता के इनपुट को क्लॉबरिंग करता है। इसके लिए Github रिपॉजिटरी यहाँ है:
Link to Github Repository
इस पुस्तकालय की मेरी मूल कार्यान्वयन व्यापक संगामिति और संदेश गुजर था, लेकिन कई संगामिति कीड़े जो मैं का समाधान नहीं कर सकता से ग्रस्त रहे। फिर जब मैं mvc
(मेरे एफआरपी-जैसे ढांचे के लिए कोड नाम, "मॉडल-व्यू-कंट्रोलर" के लिए संक्षिप्त नाम) के साथ आया, तो मुझे लगा कि rcpl
यह देखने के लिए एक उत्कृष्ट परीक्षण केस होगा कि mvc
प्राइम टाइम के लिए तैयार था या नहीं।
मैंने rcpl
का पूरा तर्क लिया और इसे एक एकल, शुद्ध पाइप में बदल दिया। this module में आपको यही मिलेगा, और कुल तर्क पूरी तरह से rcplCore
pipe के भीतर निहित है।
यह साफ है, क्योंकि अब कार्यान्वयन शुद्ध है, मैं इसे जल्दी से जांच सकता हूं और कुछ गुणों को सत्यापित कर सकता हूं!
>>> quickCheck $ \n -> length ((`evalState` initialStatus) $ P.toListM $ each (replicate n (Key 'x')) >-> runEdge (rcplCore t)) == n || n < 0
n
बार है कि मैं प्रेस की संख्या है: उदाहरण के लिए, एक संपत्ति मैं quickcheck करना चाह सकते हैं है कि वहाँ जो मैं इस तरह बनाना होगा x
कुंजी, के उपयोगकर्ता कुंजी दबाएँ प्रति ठीक एक टर्मिनल आदेश है x
कुंजी। उस परीक्षण को चलाने से निम्नलिखित आउटपुट उत्पन्न होता है:
*** Failed! Falsifiable (after 17 tests and 6 shrinks):
78
क्विक चेक ने पाया कि मेरी संपत्ति झूठी थी! इसके अलावा, क्योंकि कोड संदर्भित रूप से पारदर्शी है, क्विक चेक कम से कम पुनरुत्पादन उल्लंघन के लिए काउंटररेक्स नमूना को कम कर सकता है। 78 कुंजी प्रेस के बाद टर्मिनल ड्राइवर एक नई लाइन उत्सर्जित करता है क्योंकि कंसोल 80 वर्ण चौड़ा है, और दो अक्षर प्रॉम्प्ट द्वारा उठाए जाते हैं ("> "
इस मामले में)। इस तरह की संपत्ति है कि अगर मुझे समेकन और IO
ने मेरी पूरी प्रणाली को संक्रमित किया तो मुझे बहुत मुश्किल समझना होगा।
शुद्ध सेटअप होने के कारण किसी अन्य कारण के लिए बहुत अच्छा है: सब कुछ पूरी तरह से पुन: उत्पन्न होता है! अगर मैं सभी आने वाली घटनाओं का लॉग संग्रह करता हूं, तो किसी भी समय एक बग है, मैं घटनाओं को फिर से चला सकता हूं और टेस्ट केस को पूरी तरह से पुन: पेश कर सकता हूं जिसे मैं अपने टेस्ट सूट में जोड़ सकता हूं।
हालांकि, वास्तव में शुद्धता का सबसे महत्वपूर्ण लाभ कोड के बारे में अनौपचारिक रूप से और औपचारिक रूप से अधिक आसानी से कारण होने की क्षमता है। जब आप समीकरण से हास्केल के शेड्यूलर को हटाते हैं तो आप अपने कोड के बारे में चीजें स्थिर रूप से साबित कर सकते हैं, जिसे आप साबित नहीं कर पाएंगे कि आपको एक समवर्ती रूप से निर्दिष्ट अर्थशास्त्र के साथ एक समवर्ती रनटाइम पर निर्भर होना है। यह वास्तव में अनौपचारिक तर्क के लिए भी वास्तव में उपयोगी साबित हुआ, क्योंकि जब मैंने mvc
का उपयोग करने के लिए अपना कोड बदल दिया था, तब भी इसमें कई कीड़े थीं, लेकिन इन्हें पहले पुनरावृत्ति से जिद्दी समवर्ती बगों से डीबग करना और निकालना बहुत आसान था।
rcpl
उदाहरण विभिन्न घटकों के बीच वैश्विक राज्य साझा करने के लिए StateT
का उपयोग करता है, तो अपने प्रश्न का घना जवाब है: आप StateT
उपयोग कर सकते हैं, लेकिन केवल तभी जब आप एक एकल पिरोया संस्करण के लिए अपने सिस्टम को बदलने। सौभाग्य से यह संभव है!
मुझे लगता है कि यह प्रश्न एक विशिष्ट उत्तर देने के लिए बहुत व्यापक है। आपके द्वारा सुझाए गए रणनीतियों में से कोई भी (सिंकिंग, एफआरपी, वैश्विक युद्ध) दी गई स्थिति के लिए उपयुक्त हो सकता है। या संभवतः एक स्थानीय रूप से साझा 'आईओआरआईफ़' या 'एमवर'। या यदि गणना वास्तव में एक धागे में हैं, तो 'स्टेटटी' मोनैड ट्रांसफार्मर। यह मुझे स्पष्ट नहीं है कि 'थ्रेड" का अर्थ 'फोर्कियो' द्वारा बनाए गए वास्तविक धागे हैं, या यदि वे सख्ती से वैचारिक हैं और आप वास्तव में केवल एक थ्रेड चला रहे हैं। –
@ जोहान: चूंकि यह प्रश्न एफआरपी का उल्लेख करता है, इसलिए मुझे एक जवाब है कि एक आवेदन के माध्यम से व्यवहार या घटना धारा को साझा करने के बारे में बात करना अच्छा होगा। मुझे लगता है कि आवेदन के माध्यम से एक व्यवहार (या एक से अधिक, यदि उपयुक्त हो) थ्रेडिंग लगभग एक अच्छा विकल्प है, लेकिन मुझे जवाब में बदलने से पहले विवरणों को वास्तव में काम करना होगा। शायद अगर कुछ घंटों में कोई भी नहीं आ रहा है ... –