- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
使用 SYB 对树仅应用一次转换(而不是各处
)的最佳方法是什么?例如,在下面的简化表达式中,有多个 Var "x"
实例,我只想用 Var "y"
替换第一个实例。
数据 Exp = 变量字符串
|瓦尔国际
|加Exp Exp
|...
myExp = Val 5 `Plus` Var "x"`Plus` Val 5 `Plus` Var "x"...
这不能使用 everywhere
组合器来完成,因为它会尝试将 Var "x"
的所有实例转换为 Var "y"
.
编辑(发布后):看起来某处
就是我正在寻找的。
最佳答案
作为一名 SYB 初学者,我的答案更像是一个猜测,但似乎可行。
Neil Brown 推荐的Combinator 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
所以我制作了自己的组合器:
{-# 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])
关于Haskell 的 Scrap Your Boilerplate (SYB) - 仅应用一次转换,而不是到处应用转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16910517/
我想写一个rename替换功能String我的 AST 中的名称(代表分层标识符)与 GUID Renamer 中作为隐藏状态携带的符号表中的名称(整数)单子(monad)。 我有一个 AST a在名
在 http://web.archive.org/web/20080622204226/http://www.cs.vu.nl/boilerplate/ 中给出的示例中 -- Increase sal
与 GHC Generics 相比,是否有任何任务只能通过 SYB 才能完成,或者更容易完成? 最佳答案 GHC 泛型是一种相当冗长的方法,用于执行基本上任何查询或遍历。例如,考虑一种具有 Stmt
在 Scrap Your Boilerplate package , 在 Data.Generics.Aliases ,有些函数允许对一元和二元类型构造函数进行类型扩展。特别是对 ext1 有定义和
使用 SYB 对树仅应用一次转换(而不是各处)的最佳方法是什么?例如,在下面的简化表达式中,有多个 Var "x" 实例,我只想用 Var "y" 替换第一个实例。 数据 Exp = 变量字符串 |瓦
我在 Haskell 中发现了一个有趣的库,名为 Scrap Your Boilerplate基于paper by Simon Peyton Jones这似乎是一种有效的方法,可以用函数式编程语言编写
我可以用SYB的gfoldl一次性对listify的结果进行映射吗? 例如考虑以下代码: extractNums :: Expr -> [Int] extractNums e = map numVal
我有一个与 Show 相同的类(class)我想为每个元组类型创建一个此类的实例。通常这是通过为每个元组类型单独编写实例来完成的 instance (Show a, Show b) => Show
如何使用 SYB(或其他一些 Haskell 泛型包)在 Reader 中编写转换使用 local 的 monad修改子计算的环境? GenericM 的类型和 everywhereM (使用 a -
我想使用 SYB在 Shapeless library 中实现编写以下通用遍历函数: class Data // Perform the desired manipulation on the giv
我是一名优秀的程序员,十分优秀!