का उपयोग कर पैरामीटर के साथ एक मोनाडिक वैरैडिक फ़ंक्शन कैसे लिखना है, मैं एक मोनाडिक रिटर्न प्रकार के साथ एक वैरैडिक फ़ंक्शन बनाने की कोशिश कर रहा हूं, जिसके पैरामीटर को भी monadic संदर्भ की आवश्यकता होती है। एकहास्केल: मोनैडिक संदर्भ
असल में, मुझे मिल गया है: (जैसे printf
IO()
लौट सकते हैं, लेकिन यह अलग है कि इसके मापदंडों एक ही इलाज कर रहे हैं कि क्या यह IO()
या String
किया जा रहा समाप्त होता है है मुझे यकीन है कि कैसे है कि दूसरी बात का वर्णन करने के लिए नहीं कर रहा हूँ।) डेटा कन्स्ट्रक्टर जो कहता है, दो Char
पैरामीटर। मैं इसके बजाय दो सूचक शैली ID Char
तर्क प्रदान करना चाहता हूं, जिसे स्वचालित रूप से एक प्रकार के वर्ग उदाहरण के माध्यम से State
मोनैड से स्वचालित रूप से डीकोड किया जा सकता है। तो, get >>= \s -> foo1adic (Constructor (idGet s id1) (idGet s id2))
करने के बजाय, मैं fooVariadic Constructor id1 id2
करना चाहता हूं।
मुझे अब तक जो मिला है, वह है, लिखित हास्केल शैली अगर कोई इसे कॉपी करना चाहता है और इसके साथ गड़बड़ करना चाहता है।
सबसे पहले, बुनियादी पर्यावरण:
> {-# LANGUAGE FlexibleContexts #-}
> {-# LANGUAGE FlexibleInstances #-}
> {-# LANGUAGE MultiParamTypeClasses #-}
> import Control.Monad.Trans.State
> data Foo = Foo0
> | Foo1 Char
> | Foo2 Bool Char
> | Foo3 Char Bool Char
> deriving Show
> type Env = (String,[Bool])
> newtype ID a = ID {unID :: Int}
> deriving Show
> class InEnv a where envGet :: Env -> ID a -> a
> instance InEnv Char where envGet (s,_) i = s !! unID i
> instance InEnv Bool where envGet (_,b) i = b !! unID i
सुविधा के लिए कुछ परीक्षण डेटा:
> cid :: ID Char
> cid = ID 1
> bid :: ID Bool
> bid = ID 2
> env :: Env
> env = ("xy", map (==1) [0,0,1])
मैं इस गैर monadic संस्करण, जो केवल पहले के रूप में पर्यावरण लेता है मिल गया है पैरामीटर। यह ठीक काम करता है लेकिन यह काफी नहीं है जो मैं कर रहा हूं। उदाहरण:
$ mkFoo env Foo0 :: Foo
Foo0
$ mkFoo env Foo3 cid bid cid :: Foo
Foo3 'y' True 'y'
(मैं कार्यात्मक निर्भरता इस्तेमाल कर सकते हैं या परिवारों टाइप :: Foo
प्रकार एनोटेशन के लिए जरूरत से छुटकारा पाने के लिए अब मैं इसके बारे में परेशान नहीं कर रहा हूँ के लिए, के बाद से यह नहीं है क्या मैं इच्छुक हूँ। वैसे भी।)
> mkFoo :: VarC a b => Env -> a -> b
> mkFoo = variadic
>
> class VarC r1 r2 where
> variadic :: Env -> r1 -> r2
>
> -- Take the partially applied constructor, turn it into one that takes an ID
> -- by using the given state.
> instance (InEnv a, VarC r1 r2) => VarC (a -> r1) (ID a -> r2) where
> variadic e f = \aid -> variadic e (f (envGet e aid))
>
> instance VarC Foo Foo where
> variadic _ = id
अब, मैं एक मोनैड फ़ंक्शन चाहता हूं जो निम्नलिखित मोनैड में चलता है।
> type MyState = State Env
और मूल रूप से, मुझे नहीं पता कि मुझे आगे कैसे बढ़ना चाहिए। मैंने टाइप क्लास को विभिन्न तरीकों से व्यक्त करने की कोशिश की है (variadicM :: r1 -> r2
और variadicM :: r1 -> MyState r2
) लेकिन मैं उदाहरण लिखने में सफल नहीं हुआ हूं। मैंने उपरोक्त गैर-मोनैडिक समाधान को अपनाने का भी प्रयास किया है ताकि मैं किसी भी तरह Env -> Foo
के साथ "समाप्त हो जाऊं" जिसे मैं आसानी से MyState Foo
में बदल सकता हूं, लेकिन वहां कोई भाग्य नहीं है।
इस प्रकार मेरा सबसे अच्छा प्रयास निम्नानुसार है।
> mkFooM :: VarMC r1 r2 => r1 -> r2
> mkFooM = variadicM
>
> class VarMC r1 r2 where
> variadicM :: r1 -> r2
>
> -- I don't like this instance because it requires doing a "get" at each
> -- stage. I'd like to do it only once, at the start of the whole computation
> -- chain (ideally in mkFooM), but I don't know how to tie it all together.
> instance (InEnv a, VarMC r1 r2) => VarMC (a -> r1) (ID a -> MyState r2) where
> variadicM f = \aid -> get >>= \e -> return$ variadicM (f (envGet e aid))
>
> instance VarMC Foo Foo where
> variadicM = id
>
> instance VarMC Foo (MyState Foo) where
> variadicM = return
यह Foo0 और Foo1 लिए काम करता है, लेकिन नहीं है कि परे:
$ flip evalState env (variadicM Foo1 cid :: MyState Foo)
Foo1 'y'
$ flip evalState env (variadicM Foo2 cid bid :: MyState Foo)
No instance for (VarMC (Bool -> Char -> Foo)
(ID Bool -> ID Char -> MyState Foo))
(यहाँ मैं एनोटेशन के लिए जरूरत से छुटकारा पाने के लिए करना चाहते हैं, लेकिन वास्तव में इस सूत्रीकरण दो उदाहरणों की जरूरत है Foo
के लिए समस्याग्रस्त हो जाता है।)
मैं शिकायत को समझता हूं: मेरे पास केवल एक उदाहरण है जो Bool -> Char -> Foo
से ID Bool -> MyState (ID Char -> Foo)
पर जाता है। लेकिन मैं उदाहरण नहीं बना सकता क्योंकि यह चाहता है क्योंकि मुझे वहां कहीं MyState
की आवश्यकता है ताकि मैं ID Bool
को Bool
में बदल सकूं।
मुझे नहीं पता कि मैं पूरी तरह से ट्रैक से बाहर हूं या क्या। मुझे पता है कि मैं अपने मूल मुद्दे को हल कर सकता हूं (मैं idGet s
समकक्षों के साथ अपने कोड को प्रदूषित नहीं करना चाहता) विभिन्न तरीकों से, जैसे liftA
/liftM
- विभिन्न प्रकार के आईडी पैरामीटर के लिए स्टाइल फ़ंक्शंस, प्रकारों के साथ (a -> b -> ... -> z -> ret) -> ID a -> ID b -> ... -> ID z -> MyState ret
की तरह, लेकिन मैंने इस बारे में सोचने में बहुत अधिक समय बिताया है। :-) मैं जानना चाहता हूं कि यह वैरिएडिक समाधान कैसा दिखना चाहिए।
चूंकि आप स्पष्ट रूप से 'आवेदक' समाधान की तलाश नहीं कर रहे हैं, इसलिए मैं इसे टिप्पणियों में जोड़ रहा हूं: https://gist.github.com/f8e5d1ecf20ea09a8b36 –