2015-02-19 4 views
7

मैं एक ढांचा लिख ​​रहा हूं, जहां मुख्य कार्य उपयोगकर्ता को a -> [b] के प्रकार के बारे में पूछता है।क्या रीडर के समानता और सामान्य कार्य का उपयोग करने के लिए कोई "मानक" तरीका है?

हालांकि, क्योंकि है कि समारोह काफी जटिल हो सकता है, इसके कार्यान्वयन अक्सर इस तरह दिख सकता:

fn a = extractPartOfAAndConvert a ++ extractAnotherPartofAAndConvert a 

इसलिए मैं Reader कि लड़ने के लिए एक अच्छा, मुहावरेदार विचार का उपयोग कर सकते लगा। हालांकि, साथ ही मुझे एहसास हुआ कि कुछ लोग एक मोनड का उपयोग नहीं करना चाहते हैं।

प्रयोग करते हैं, मैं इस समाधान से तैयार किया है:

class Iso a b where 
    isoFrom :: a -> b 
    isoTo :: b -> a 

instance Iso a a where 
    isoFrom = id 
    isoTo = id 

instance Iso (a -> b) (Reader a b) where 
    isoFrom f = reader f 
    isoTo m = runReader m 

कौन सा बदले में मुझे क्या करना अनुमति देता है:

testCallback :: MyState -> Callback -> MyState 
testCallback myState cb = cb myState 

-- The important signature 
testCallbackGeneric :: Iso Callback a => MyState -> a -> MyState 
testCallbackGeneric myState cb = (isoTo cb) myState 

callbackFunction :: Callback 
callbackFunction s = s + 10 

callbackMonad :: Reader MyState MyState 
callbackMonad = do 
    x <- ask 
    return $ x - 10 

----------- 

let myStateA = testCallback myState callbackFunction 
-- let myStateB = testCallback myState callbackMonad -- won't work, obviously 
let myStateC = testCallbackGeneric myState callbackFunction 
let myStateD = testCallbackGeneric myState callbackMonad 

हालांकि, मुझे लगता है कि बहुत ज्यादा है कि मैं पहिया पुनर्रचना कर रहा हूँ।

क्या रीडर के समतुल्य को व्यक्त करने का कोई तरीका है कि इस तरह के सामान्य कार्यों को आसानी से लिखने के बिना अपना खुद का प्रकार वर्ग बनाने के लिए?

+0

एक और बात है कि क्या यह इस तरह के व्यापक हस्ताक्षर, जहां उपयोगकर्ता केवल preferrable में बदल सकते हैं प्रदान करने के लिए वास्तव में worthwile है रास्ता, बस उदाहरण की तरह करता है। मुझे लगता है कि ऐसा कोई कारण नहीं है कि बॉयलरप्लेट को उपयोगकर्ता से बचाया/नहीं लिया जाना चाहिए। –

+1

आप 'मोनाड रीडर' बाधा का उपयोग कर सकते हैं, जिसके लिए फ़ंक्शंस के लिए पहले से मौजूद एक उदाहरण मौजूद है। यदि आप 'f = do {a <- पूछते हैं; $ 2 * ए + 3 * ए} वापस करें, फिर आप इसे 'एफ 1 == 5' या किसी भी' रीडर 'फ़ंक्शन में' f :: MonadReader Int m => m Int' के रूप में फ़ंक्शन के रूप में उपयोग कर सकते हैं। यह 'Int -> Int' या' Reader Int Int 'के लिए विशेषज्ञ हो सकता है। – bheklilr

+0

@bheklilr * जिसके लिए पहले से ही कार्यों के लिए एक उदाहरण मौजूद है। * यह। यही वह था जो मैं पूरे समय लापता था! इसे एक उत्तर के रूप में लिखें ताकि मैं इसे ऊपर उठा सकूं! :) (और हाँ 'कॉलबैक' सिर्फ 'मायस्टेट -> माइस्टेट', और' मायस्टेट ~ Int') –

उत्तर

10

आप इस तथ्य का उपयोग कर सकते हैं कि फ़ंक्शन मोनड (->) r में में परिभाषित MonadReader r के लिए पहले से ही एक उदाहरण है। तुम बस MonadReader बाधा का उपयोग कर कार्यों लिखने और उन्हें या तो सामान्य कार्यों के रूप में या अन्य ReaderT monads में उपयोग कर सकते हैं:

f :: MonadReader Int m => m Int 
f = do 
    a <- ask 
    return $ 2 * a + 3 * a 

normally :: Int 
normally = f 1 
-- normally == 5 

readerly :: Reader Int Int 
readerly = do 
    result <- f 
    return $ 2 * result 

> runReader f 1 
5 
> runReader readerly 1 
10 
संबंधित मुद्दे

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