2013-06-04 4 views
5

केवल एक बार के बजाय everywhere के एक पेड़ से एक परिवर्तन लागू SYB का उपयोग करने के लिए सबसे अच्छा तरीका क्या है परिवर्तन लागू करने के? उदाहरण के लिए, निम्नलिखित सरलीकृत अभिव्यक्ति में, Var "x" के कई उदाहरण हैं, और मैं केवल पहले उदाहरण को Var "y" के साथ प्रतिस्थापित करना चाहता हूं।हास्केल के स्क्रैप आपका बॉयलरप्लेट (SYB) - केवल एक बार के बजाय हर जगह

data Exp = Var String | Val Int | Plus Exp Exp |...

myExp = Val 5 `Plus` Var "x" `Plus` Val 5 `Plus` Var "x" ...

यह everywhere Combinator का उपयोग कर के बाद से यह Var "y" को Var "x" के सभी उदाहरणों को बदलने की कोशिश करेंगे नहीं किया जा सकता।

संपादित करें (पोस्ट करने के बाद): ऐसा लगता है जैसे मैं somewhere के लिए क्या देख रहा हूँ।

उत्तर

3

एक एसईबी शुरुआती होने के नाते, मेरा जवाब एक अनुमान की तरह है, लेकिन काम करने लगता है।

नील ब्राउन द्वारा अनुशंसित कॉम्बिनेटर somewhere शायद वही नहीं करता जो आप चाहते हैं। यह defined रूप

-- | Apply a monadic transformation at least somewhere 
somewhere :: MonadPlus m => GenericM m -> GenericM m 

-- We try "f" in top-down manner, but descent into "x" when we fail 
-- at the root of the term. The transformation fails if "f" fails 
-- everywhere, say succeeds nowhere. 
-- 
somewhere f x = f x `mplus` gmapMp (somewhere f) x 

जहां

-- | Transformation of at least one immediate subterm does not fail 
gmapMp :: forall m. MonadPlus m => (forall d. Data d => d -> m d) -> a -> m a 

लेकिन हम में अधिकतम एक बार को बदलने के लिए की जरूरत है। इस के लिए ऐसा लगता है कि gmapMo बेहतर होगा:

-- | Transformation of one immediate subterm with success 
gmapMo :: forall m. MonadPlus m => (forall d. Data d => d -> m d) -> a -> m a 

तो मैं अपने ही Combinator बनाया: प्रतिस्थापन विफल रहता है

{-# LANGUAGE DeriveDataTypeable, RankNTypes #-} 
import Control.Monad 
import Data.Maybe (fromMaybe) 
import Data.Data 
import Data.Typeable (Typeable) 
import Data.Generics.Schemes 
import Data.Generics.Aliases 

-- | Apply a monadic transformation once. 
once :: MonadPlus m => GenericM m -> GenericM m 
once f x = f x `mplus` gmapMo (once f) x 

है, यह रिटर्न mzero, अन्यथा यह प्रतिस्थापित परिणाम देता है। यदि आप अगर प्रतिस्थापन (कोई मेल नहीं) में विफल रहता है परवाह नहीं है, आप की तरह

once' :: (forall a. Data a => a -> Maybe a) -> (forall a. Data a => a -> a) 
once' f x = fromMaybe x (once f x) 
इन के साथ

कुछ इस्तेमाल कर सकते हैं, हम कुछ प्रतिस्थापन कर सकते हैं:

data Exp = Var String | Val Int | Plus Exp Exp 
    deriving (Show, Typeable, Data) 

myExp = Val 5 `Plus` Var "x" `Plus` Val 5 `Plus` Var "x" 

replM :: (MonadPlus m) => Exp -> m Exp 
replM (Var "x") = return $ Var "y" 
replM t   = mzero 

main = do 
    -- `somewhere` doesn't do what we want: 
    print $ (somewhere (mkMp replM) myExp :: Maybe Exp) 

    -- returns `Just ..` if the substitution succeeds once, 
    -- Nothing otherwise. 
    print $ (once (mkMp replM) myExp :: Maybe Exp) 
    -- performs the substitution once, if possible. 
    print $ (once' (mkMp replM) myExp :: Exp) 

    -- Just for kicks, this returns all possible substitutions 
    -- where one `Var "x"` is replaced by `Var "y"`. 
    print $ (once (mkMp replM) myExp :: [Exp]) 
+0

उत्कृष्ट समाधान! ठीक वही जो मेरे द्वारा खोजा जा रहा था। बहुत - बहुत धन्यवाद! – user1546806

+0

यह काम मेरे कोड पर करने के लिए, मुझे एक बार फिर से लिखना था 'एक बार एफ x = f x \ 'mplus \' gmapMo (एक बार f) x'। – user1546806

+0

@ user1546806 हाँ, क्षमा करें, यह मूर्खतापूर्ण गलती थी। मैं जवाब सही कर दूंगा। –

2

हाँ, मुझे लगता है कि somewhere (mkMp mySpecificFunction) इसे करना चाहिए, यदि आप मोनाडप्लस मोनैड का उपयोग करते हैं और इसे खोजते हैं तो यह आपको सफल बनाता है। इस तरह, जब आप समाप्त कर -

एक लचीला लेकिन hacky विकल्प एक राज्य इकाई के साथ everywhereM उपयोग करने के लिए है कि एक Boolean (या Maybe MyFunc की दुकान या जो कुछ भी) स्टोर कर सकते हैं और राज्य True या Just myFunc किया जा रहा है पर निर्भर करता है परिवर्तन लागू है (उदाहरण के लिए एक बार परिवर्तन लागू करने के बाद), आप बस False/Nothing होने के लिए राज्य को बदल दें।

+0

धन्यवाद, @NeilBrown। क्या आप पहले दृष्टिकोण को थोड़ा और विस्तारित कर सकते हैं? मैंने यह [लाइब्रेरी] (http://web.engr.oregonstate.edu/~erwig/reclib/) पाया, जो ऑनटाइम रूपांतरण निर्दिष्ट करने के लिए मोनाडप्लस का भी उपयोग करता है, लेकिन यह 'कहीं और' का उपयोग नहीं करता है। दूसरा दृष्टिकोण काम करता है, लेकिन हम उस मार्ग पर जाना नहीं चाहते हैं। – user1546806

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