采用这种简单的数据类型(来自Uniplate documentation):
data Expr = Val Int
| Neg Expr
| Add Expr Expr
我想检查表达式树是否包含特定操作(在我们的案例中为Neg
和Add
)。
如果我们为Uniplate
派生Expr
,我们就可以使用universe
来编写这两个简单的函数:
hasNeg :: Expr -> Bool
hasNeg e = not $ null [() | Neg{} <- universe e]
hasAdd :: Expr -> Bool
hasAdd e = not $ null [() | Add{} <- universe e]
我想提取公共代码并写一些&#34; generic&#34;函数将接受有关构造函数的一些信息,但我甚至无法想到匹配的类型签名,这通常是一个不好的标志。这个功能是否有意义,以及实现它的正确方法是什么?
谢谢!
答案 0 :(得分:3)
Control.Lens.Plated
具有与uniplate
类似的API(性能也大致相同),但使用lens
可以将prism用作第一类构造函数:
{-# LANGUAGE TemplateHaskell #-}
import Control.Applicative
import Control.Lens
import Control.Lens.Extras
data Expr = Val Int
| Neg Expr
| Add Expr Expr deriving (Eq, Show)
instance Plated Expr where
plate f (Val i) = pure (Val i)
plate f (Neg e) = Neg <$> f e
plate f (Add a b) = Add <$> f a <*> f b
makePrisms ''Expr -- derives _Val, _Neg and _Add prisms
hasNeg :: Expr -> Bool
hasNeg = any (is _Neg) . universe
hasPrism :: Prism' Expr a -> Expr -> Bool
hasPrism p = any (is p) . universe
hasAdd :: Expr -> Bool
hasAdd = hasPrism _Add
hasNegNeg :: Expr -> Bool
hasNegNeg = hasPrism (_Neg . _Neg) -- matches (Neg (Neg x))