एक एसईबी शुरुआती होने के नाते, मेरा जवाब एक अनुमान की तरह है, लेकिन काम करने लगता है।
नील ब्राउन द्वारा अनुशंसित कॉम्बिनेटर 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])
उत्कृष्ट समाधान! ठीक वही जो मेरे द्वारा खोजा जा रहा था। बहुत - बहुत धन्यवाद! – user1546806
यह काम मेरे कोड पर करने के लिए, मुझे एक बार फिर से लिखना था 'एक बार एफ x = f x \ 'mplus \' gmapMo (एक बार f) x'। – user1546806
@ user1546806 हाँ, क्षमा करें, यह मूर्खतापूर्ण गलती थी। मैं जवाब सही कर दूंगा। –