我想使用A的一些镜头创建一个函数A -> Bool
。例如:
data A = A { _foo :: Int, _bar :: Int }
makeLenses ''A
l :: [A]
l' = filter (\a -> a^.foo > 100) l
过滤谓词看起来有点块状。 ((>100).(^.foo))
并没有好多少。没有镜头,我会使用((>100) . foo)
。
使用lens
创建此类谓词有一种很好的方法吗?理想情况下,它还允许使用(\a -> a^.foo > 100 && a^.bar < 50)
等谓词。
答案 0 :(得分:4)
我认为((>100).(^.foo))
可能只是使用标准运算符可以做到的最好。如果您愿意为镜头定义新的比较运算符,您可以执行以下操作:
import Control.Lens hiding ((.>))
import Control.Monad (liftM2)
import Control.Monad.Reader (MonadReader)
import Data.Function (on)
(.==) :: (MonadReader s m, Eq a) => Getting Bool s a -> a -> m Bool
(.==) l = views l . (==)
infix 4 .==
(.==.) :: (MonadReader s m, Eq a) => Getting a s a -> Getting a s a -> m Bool
(.==.) = liftM2 (==) `on` view
infix 4 .==.
(.<) :: (MonadReader s m, Ord a) => Getting Bool s a -> a -> m Bool
(.<) l = views l . flip (<)
infix 4 .<
(.<.) :: (MonadReader s m, Ord a) => Getting a s a -> Getting a s a -> m Bool
(.<.) = liftM2 (<) `on` view
infix 4 .<.
(.<=) :: (MonadReader s m, Ord a) => Getting Bool s a -> a -> m Bool
(.<=) l = views l . flip (<=)
infix 4 .<=
(.<=.) :: (MonadReader s m, Ord a) => Getting a s a -> Getting a s a -> m Bool
(.<=.) = liftM2 (<=) `on` view
infix 4 .<=.
(.>) :: (MonadReader s m, Ord a) => Getting Bool s a -> a -> m Bool
(.>) l = views l . flip (>)
infix 4 .>
(.>.) :: (MonadReader s m, Ord a) => Getting a s a -> Getting a s a -> m Bool
(.>.) = liftM2 (>) `on` view
infix 4 .>.
(.>=) :: (MonadReader s m, Ord a) => Getting Bool s a -> a -> m Bool
(.>=) l = views l . flip (>=)
infix 4 .>=
(.>=.) :: (MonadReader s m, Ord a) => Getting a s a -> Getting a s a -> m Bool
(.>=.) = liftM2 (>=) `on` view
infix 4 .>=.
(.&&.) :: Monad m => m Bool -> m Bool -> m Bool
(.&&.) = liftM2 (&&)
infix 3 .&&.
(.||.) :: Monad m => m Bool -> m Bool -> m Bool
(.||.) = liftM2 (||)
infix 3 .||.
操作员选择背后的逻辑是,点表示有镜头的一侧,因此您可以写foo .== 5
或foo .==. bar
(foo
和bar
是镜头)。不幸的是,lens
包还定义了自己的(.<)
运算符,所以也许其他一些命名约定会更好。这只是我想到的第一个想法。
使用这些新操作符,您可以编写
之类的内容l' = filter (foo .> 100 .&&. bar .< 50) l