तो इसे समझने का सबसे अच्छा तरीका यह है। नीचे इसके बजाय foldlM
उपयोग का कार्यान्वयन foldl
है foldr
। यह एक अच्छा अभ्यास है, इसे आज़माएं और बाद में समाधान के लिए आऊंगा जो मैं सुझाऊंगा। उदाहरण ने मुझे इसे प्राप्त करने के लिए किए गए सभी तर्क की व्याख्या की, जो आपके से अलग हो सकता है, और पूर्वाग्रह हो सकता है क्योंकि मैं पहले से ही एक फ़ंक्शन संचायक का उपयोग करने के बारे में जानता हूं।
चरण 1 : के foldlM
संदर्भ में लिखने की कोशिश करते हैंfoldl
-- this doesn't compile because f returning type is (m b) and not just (b)
foldlM :: (Foldable t, Monad m) => (b -> a -> m b) -> b -> t a -> m b
foldlM f z0 xs = foldl f z0 xs
-- So let substitute f by some undefined f'
foldlM :: (Foldable t, Monad m) => (b -> a -> m b) -> b -> t a -> m b
foldlM f z0 xs = foldl f' z0 xs
where f' = undefined
-- cool, but f' should use f somehow in order to get the monadic behaviour
foldlM :: (Foldable t, Monad m) => (b -> a -> m b) -> b -> t a -> m b
foldlM f z0 xs = foldl f' z0 xs
where f' b a = f somethingIDontkNow
यहां आपको पता चलता है कि f'
शुद्ध है और आपको f
टाइप मैच का परिणाम निकालना होगा । एक मौद्रिक मूल्य को 'निकालने' का एकमात्र तरीका >>=
ऑपरेटर के पास है, लेकिन इस तरह के ऑपरेटर को इसके उपयोग के बाद सही लपेटने की आवश्यकता होती है।
इसलिए एक निष्कर्ष के रूप में: हर बार जब आप समाप्त होते हैं तो मैं इस भिक्षु को पूरी तरह से खोल देना चाहता हूं , बस छोड़ देना चाहिए। सही तरीका नहीं है
चरण 2 : चलिए लिखने की कोशिश foldlM
करते हैं, foldl
लेकिन पहली बार प्रयोग करने योग्य के []
रूप में, क्योंकि यह पैटर्न मैच के लिए आसान है (यानी हम वास्तव में उपयोग करने के लिए नहीं है fold
)
-- This is not very hard. It is pretty standard recursion schema. :)
foldlM' :: (Monad m) => (b -> a -> m b) -> b -> [a] -> m b
foldlM' f z0 [] = return z0
foldlM' f z0 (x:xs) = f z0 x >>= \c -> foldlM' f c xs
ठीक है, यह आसान था। foldl
सूचियों के लिए सामान्य परिभाषा के साथ परिभाषा की तुलना करें
foldlM' :: (Monad m) => (b -> a -> m b) -> b -> [a] -> m b
foldlM' f z0 [] = return z0
foldlM' f z0 (x:xs) = f z0 x >>= \c -> foldlM' f c xs
myfoldl :: (b -> a -> b) -> b -> [a] -> b
myfoldl f z0 [] = z0
myfoldl f z0 (x:xs) = foldl f (f z0 x) xs
ठंडा!! वे बहुत अधिक समान हैं। तुच्छ मामला ठीक उसी चीज के बारे में है। पुनरावर्ती मामले में थोड़ा अलग है, आप कुछ तरह के और अधिक लिखने के लिए करना चाहते हैं: foldlM' f (f z0 x) xs
। लेकिन चरण 1 के अनुसार संकलित नहीं है, तो आप सोच सकते हैं ठीक है, मैं आवेदन नहीं करना चाहता f
, बस इस तरह की गणना को पकड़कर इसके साथ रचना करना चाहता हूं >>=
। मैं कुछ और लिखना चाहूंगा foldlM' f (f z0 x >>=) xs
अगर उसमें समझदारी होती ...
चरण 3 यह महसूस करें कि आप जो जमा करना चाहते हैं वह एक फ़ंक्शन संरचना है और परिणाम नहीं। ( यहां मैं शायद इस तथ्य से पूर्वाग्रह कर रहा हूं कि मैं पहले से ही जानता था क्योंकि आपने इसे पोस्ट किया है )।
foldlM :: (Foldable t, Monad m) => (b -> a -> m b) -> b -> t a -> m b
foldlM f z0 xs = foldl f' initFunc xs
where initFunc = undefined :: b -> m b
f' = undefined :: (b -> m b) -> a -> (b -> m b) -- This type signature can be deduce because f' should be applied to initFunc and a's from t a.
initFunc
चरण 2 (पुनरावर्ती परिभाषा) से हमारे ज्ञान के प्रकार का उपयोग करके हम उसे घटा सकते हैं initFunc = return
। यह f'
जानने और f'
उपयोग करने की परिभाषा को पूरा किया जा सकता है ।f
>>=
foldlM :: (Foldable t, Monad m) => (b -> a -> m b) -> b -> t a -> m b
foldlM f z0 xs = foldl f' return xs z0
-- ^^^^^^
-- |- Initial value
where f' b a = \bvalue -> b bvalue >>= \bresult -> f bresult a -- this is equivalent to (b >=> \result -> f result a) which captures the sequence behaviour of the implementation
-- ^ ^^^^^^ ^^^^^^^
-- | | |- This is the result of previous computation
-- | |- f' should return a function b -> m b. Any time you have to return a function, start writing a lambda
-- |- This b is the accumulated value and has type b -> m b
-- Following the types you can write this with enough practise
जैसा कि आप देख सकते हैं, यह करना मुश्किल नहीं है। इसे अभ्यास की आवश्यकता है, लेकिन मैं एक पेशेवर हैस्केल डेवलपर नहीं हूं और मैं इसे स्वयं कर सकता हूं, यह अभ्यास की बात है