किसी के लिए इस तरह की तहलएम की परिभाषा लिखने के लिए किस तरह का ज्ञान या प्रशिक्षण आवश्यक है? [बन्द है]


9

हाल ही में, मैं अपने कुछ वास्तविक मामले उत्पादन प्रणाली में हास्केल का उपयोग करने की कोशिश कर रहा हूं। हास्केल प्रकार प्रणाली वास्तव में मुझे बहुत मदद करती है। उदाहरण के लिए, जब मुझे महसूस हुआ कि मुझे कुछ प्रकार के फ़ंक्शन की आवश्यकता है

f :: (Foldable t, Monad m) => ( a-> b -> m b) -> b -> t a -> m b

वास्तव में जैसे कार्य हैं foldM, foldlMऔर foldrM

हालाँकि, मुझे क्या झटका लगा, इन कार्यों की परिभाषा क्या है, जैसे:

foldlM :: (Foldable t, Monad m) => (b -> a -> m b) -> b -> t a -> m b
foldlM f z0 xs = foldr f' return xs z0
  where f' x k z = f z x >>= k

इसलिए फ़ंक्शन f'प्रकार का होना चाहिए:

f' :: a -> b -> b

के रूप में आवश्यक है foldr, तो bतरह का होना चाहिए *-> m *, इसलिए पूरी परिभाषा foldlMसमझ में आ सकती है।

एक अन्य उदाहरण में liftA2और की परिभाषाएँ शामिल हैं<*>

(<*>) :: f (a -> b) -> f a -> f b
(<*>) = liftA2 id

liftA2 :: (a -> b -> c) -> f a -> f b -> f c
liftA2 f x = (<*>) (fmap f x)

मैंने स्रोत कोड में झांकने से पहले अपने कुछ समाधानों की कोशिश की। लेकिन अंतर इतना बड़ा है कि मुझे नहीं लगता कि मैं कभी भी इस समाधान के साथ आ सकता हूं, चाहे मैं भविष्य में कोड की कितनी पंक्तियां लिखूं।

तो मेरा प्रश्न यह है कि किसी ऐसे उच्च स्तर पर तर्क करने के लिए किसी व्यक्ति के लिए किस तरह का ज्ञान या कौन सी विशिष्ट गणित शाखा आवश्यक है।

मुझे पता है कि श्रेणी सिद्धांत कुछ मदद की पेशकश कर सकता है और मैं लंबे समय से इस महान व्याख्यान का पालन ​​कर रहा हूं और अभी भी इस पर काम कर रहा हूं ।


13
हास्केल एक भाषा है। इसके कई शब्द हैं, और उनमें से अधिकांश शब्दों का उपयोग विभिन्न तरीकों से किया जा सकता है। जब आप एक नई भाषा सीख रहे हैं, तो कई वर्षों तक कई वाक्य और मुहावरे समझ में नहीं आते हैं। लेकिन जितना अधिक आप इसका उपयोग करते हैं, उतना ही आप परिचित पैटर्न देखते हैं, और आपके द्वारा एक बार सोचा जाने वाली चीजें डराने और उन्नत करने के लिए स्वाभाविक रूप से आती हैं। आराम करें।
लूकी

जवाबों:


3

सामान्य तौर पर, तर्क आदि, मैं कल्पना करूँगा। लेकिन आप इसे करके भी सीख सकते हैं। :) समय के साथ आप कुछ पैटर्न नोटिस करते हैं, कुछ तरकीबें अपनाते हैं।

इस तरह foldrएक अतिरिक्त तर्क बात के साथ। कुछ कार्यों में तह ताकि वे के माध्यम से जोड़ा जा सकता है के रूप में देखते .हैं और id(जो कभी कभी वास्तव में कर रहे हैं <=<और return),

foldr g z xs  =  foldr ($) z . map g $ xs
              =  foldr (.) id (map g xs) z
         ~/=  foldr (<=<) return (map g xs) z
{-
  (\f -> f . f) :: (a -> a) -> (a -> a)

  (\f -> f <=< f) :: Monad m => (a -> m a) -> (a -> m a)
                            (still just a type, not a kind)
-}

कुछ लोगों को इसे सरल, वाक्यविन्यास शब्दों में समझना आसान लगता है, जैसा कि

foldr g z [a,b,c,...,n] s =
     g a (foldr g z [b,c,...,n]) s

इसलिए जब gअपने दूसरे तर्क में गैर-सख्त होता है s, तो एक उदाहरण के रूप में, हम दाईं ओर मोड़ रहे हैं, भले ही बाईं ओर से एक राज्य के रूप में सेवा कर सकते हैं।


1
बहुत बहुत धन्यवाद, मैं यह पता लगाने की कोशिश कर रहा था कि क्या यह परिभाषा अद्वितीय है और यहां क्लीसली रचना के उपयोग की उम्मीद नहीं थी। यह उत्तर वास्तव में मेरी शंका का समाधान करता है।
थियोडोरा

आपका स्वागत है। :)
नेस

4

तो इसे समझने का सबसे अच्छा तरीका यह है। नीचे इसके बजाय 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

जैसा कि आप देख सकते हैं, यह करना मुश्किल नहीं है। इसे अभ्यास की आवश्यकता है, लेकिन मैं एक पेशेवर हैस्केल डेवलपर नहीं हूं और मैं इसे स्वयं कर सकता हूं, यह अभ्यास की बात है


1
मैं वास्तव में नहीं देखता कि क्या एक बाएँ गुना आसान बनाता है यहाँ एक सही गुना से समझने के लिए। अनंत संरचनाओं के लिए एक उपयोगी परिणाम पैदा करने और विशिष्ट Monadउदाहरणों के लिए कुशल होने के लिए सही गुना बहुत अधिक है ।
dfeuer

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

3

फ़ंक्शन लिखने के लिए आपको गणित में किसी विशिष्ट ज्ञान की आवश्यकता नहीं है foldM। मैं पहले से ही 4 वर्षों के लिए उत्पादन में हास्केल का उपयोग कर रहा हूं, और मैं इस परिभाषा को समझने में भी संघर्ष कर रहा हूं foldM। लेकिन ऐसा ज्यादातर इसलिए है क्योंकि यह खराब लिखा गया है। कृपया, इसे व्यक्तिगत दोष के रूप में न लें यदि आप कुछ अस्पष्ट कोड को नहीं समझ सकते हैं। यहाँ का अधिक पठनीय संस्करण हैfoldlM

foldlM
    :: forall t m a b .
       (Foldable t, Monad m)
    => (b -> a -> m b)  -- ^ Monadic action
    -> b                -- ^ Starting accumulator
    -> t a              -- ^ List of values
    -> m b              -- ^ Computation result inside a monad
foldlM f z xs = (foldr step pure xs) z
  where
    step :: a -> (b -> m b) -> b -> m b
    step cur next acc = do
        result <- f acc cur
        next result

यह फ़ंक्शन अभी भी सबसे आसान नहीं है। अधिकतर क्योंकि इसमें गैर-विशिष्ट उपयोग होता है foldrजहां मध्यवर्ती संचयक एक फ़ंक्शन होता है। लेकिन आप कुछ ऐसे मेन्स देख सकते हैं जो इस तरह की परिभाषा को अधिक पठनीय बनाते हैं:

  1. समारोह तर्क के बारे में टिप्पणियाँ।
  2. बेहतर तर्क नाम (अभी भी छोटे और मुहावरेदार, लेकिन वे कम से कम अधिक पठनीय हैं)।
  3. फ़ंक्शन के स्पष्ट प्रकार पर हस्ताक्षर where(ताकि आप तर्कों के आकार को जानते हैं)।

इस तरह के फंक्शन को देखने के बाद, आप अब स्टेप-बाय-स्टेप का विस्तार करने के लिए इक्विशनल रीज़निंग तकनीक का प्रदर्शन कर सकते हैं और देखें कि यह कैसे काम करता है। ऐसे कार्यों के साथ आने की क्षमता अनुभव के साथ आती है। मेरे पास मजबूत गणितज्ञ कौशल नहीं है, और यह फ़ंक्शन एक विशिष्ट हास्केल फ़ंक्शन नहीं है। लेकिन आपके पास जितना अधिक अभ्यास होगा, उतना ही बेहतर होगा :)

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.