2012-03-13 9 views
13

दो monads, Monad m और Monad n दिए गए, मैं m (n a)n (m a) में बदलना चाहता हूं। लेकिन ऐसा कोई सामान्य तरीका नहीं है क्योंकि (>>=) और return दोनों केवल एक मोनैड प्रकार से संबंधित हैं, और हालांकि (>>=) एक मोनैड से सामग्री निकालने की अनुमति देता है, तो आपको उन्हें उसी मोनैड प्रकार पर पैक करना होगा ताकि यह परिणाम मूल्य हो।monads repacking - कोई सामान्य तरीका?

हालांकि, अगर हम m को एक निश्चित प्रकार पर सेट करते हैं, तो नौकरी आसान हो जाती है। एक उदाहरण के रूप Maybe लें:

reorder :: (Monad n) => Maybe (n a) -> n (Maybe a) 
reorder Nothing = return Nothing 
reorder (Just x) = do 
    x' <- x 
    return $ Just x' 

या एक सूची: देखने के लिए

reorder :: (Monad n) => [n a] -> n [a] 
reorder [] = return [] 
reorder (x:xs) = do 
    x' <- x 
    xs' <- reorder xs 
    return (x':xs') 

कठिन नहीं, हम यहाँ एक पैटर्न मिल गया है। और अधिक स्पष्ट होने के लिए, एक Applicative तरीके से लिखते हैं, और यह प्रत्येक तत्व के लिए डेटा निर्माता को लागू करने से अधिक नहीं है:

reorder (Just x) = Just <$> x 
reorder (x:xs) = (:) <$> x <*> (reorder xs) 

मेरे सवाल यह है: एक haskell typeclass पहले से ही इस तरह के आपरेशनों का वर्णन करने के लिए मौजूद है, या मैं क्या करता है खुद पहिया का आविष्कार करना है?

मुझे जीएचसी दस्तावेज में एक संक्षिप्त खोज थी, और इस विषय के लिए कुछ भी उपयोगी नहीं मिला।

sequenceA :: (Traversable t, Applicative f) => t (f a) -> f (t a) 

GHC भी समर्थन स्वचालित रूप से पाने उदाहरण के लिए प्रदान करता है::

उत्तर

14

Data.Traversable आप क्या देख रहे हैं के लिए प्रदान करता

{-# LANGUAGE DeriveFunctor, DeriveFoldable, DeriveTraversable #-} 
import Data.Foldable 
import Data.Traversable 

data List a = Nil | Cons a (List a) 
    deriving(Functor, Foldable, Traversable) 
+0

यह, ज़ाहिर है, केवल तभी काम करता है जब आपका बाहरी प्रकार का कन्स्ट्रक्टर 'ट्रैवर्सबल' (सभी 'मोनाद नहीं हैं)। बोनस यह है कि आंतरिक व्यक्ति को केवल 'आवेदक' होना चाहिए। –

5

(Monad m, Monad n) => m (n a) -> n (m a) के लिए hoogle पर एक त्वरित खोज मुझे पता चला है कई कार्य देखते हैं कि कि (मोटे तौर पर) उस हस्ताक्षर का पालन करें जिसे आप ढूंढ रहे हैं:

  1. Data.Traversable.sequence :: (Traversable t, Monad m) => t (m a) -> m (t a);
  2. Data.Traversable.sequenceA :: Applicative f => t (f a) -> f (t a);
  3. Contro.Monad.sequence :: Monad m => [m a] -> m [a] (Prelude द्वारा भी निर्यात किया गया)।

दोनों [a] और Maybe a traversable की घटनाएं होती हैं, तो आपके पुन: व्यवस्थित करें कार्यों Data.Traversable.sequence का सिर्फ अनुप्रयोग हैं। एक उदाहरण में, लिख सकते हैं:

ghci> (Data.Traversable.sequence $ Just (return 1)) :: IO (Maybe Int) 
Just 1 
it :: Maybe Int 

ghci> (Data.Traversable.sequence $ Just ([1])) :: [Maybe Int] 
[Just 1] 
it :: [Maybe Int] 

ghci> (Data.Traversable.sequence $ [Just 1]) :: Maybe [Int] 
Just [1] 
it :: Maybe [Int] 

फिर भी नोट करें कि विशिष्ट वर्ग घोषणा class (Functor t, Foldable t) => Traversable t है, और यदि आप अन्य दो कार्यों के प्रकार पर भी लग रहे हैं, यह आप के लिए क्या देख रहे हैं की तरह लगता है नहीं है संभावित रूप से प्रतिबंध/पूर्व शर्त के बिना सभी monads m और n के लिए एक सामान्य तरीके से किया जा सकता है।

1

सभी मोनाड्स इस तरह से यात्रा नहीं कर सकते हैं। (सरलीकृत) एडवर्ड Kmett के distributive पैकेज प्रकार कंस्ट्रक्टर्स है कि तुम क्या इच्छा के समान है के लिए एक typeclass Distributive प्रदान करता है:

class Functor g => Distributive g where 
    distribute :: Functor f => f (g a) -> g (f a) 
    collect  :: Functor f => (a -> g b) -> f a -> g (f b) 

डिफ़ॉल्ट परिभाषाओं distribute और collect के लिए प्रदान की जाती हैं, एक-दूसरे के संदर्भ में लिखा है।मुझे यह पैकेज searching hayoo for the desired type signature द्वारा मिला।

4

यह सामान्य रूप से नहीं किया जा सकता है: यह एक मोनैड का एक अच्छा उदाहरण है जो ऐसा नहीं कर सकता पाठक (या फ़ंक्शन) मोनैड है। यही कारण है कि निम्नलिखित समारोह की आवश्यकता होती है definable मानेंगे:

impossible :: (r -> IO a) -> IO (r -> a) 

यह साबित होता है कि एक समारोह लागू नहीं किया जा सकता है सरल नहीं है। लेकिन सहजता से, समस्या यह है कि जो कुछ भी IO किया जाता है, उसे वापस करने के लिए किया जाना चाहिए इससे पहले कि हम जानते हैं कि r पैरामीटर है। तो impossible readFile को यह पता चलने से पहले कि कौन सी फाइलें खुलती हैं, एक शुद्ध कार्य FilePath -> String उत्पन्न करना होगा। जाहिर है, कम से कम, impossible वह नहीं कर सकता जो आप चाहते हैं।

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