私はSYB初心者であり、私の答えは推測のようですが、うまくいくようです。
コンビネータsomewhere
ニールブラウンが推薦するのは、おそらくあなたが望むだけではないでしょう。それは
-- | 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
-- | 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
としてdefinedだ。しかし、私たちは、最高1回を変換する必要があります。このためにはgmapMo
が良くなるようだ:
-- | Transformation of one immediate subterm with success
gmapMo :: forall m. MonadPlus m => (forall d. Data d => d -> m d) -> a -> m a
だから私は自分のコンビネータをした:置換が失敗した場合
{-# 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
私のコードでこれを動作させるには、 'once f x = f x \' mplus \ 'gmapMo(once f)x'と書き直す必要がありました。 – user1546806
@ user1546806はい、申し訳ありませんが、それは愚かな間違いでした。私は答えを修正します。 –