Build predicates with lenses

I want to create an A -> Bool function using some A. lenses. For example:

 data A = A { _foo :: Int, _bar :: Int } makeLenses ''A l :: [A] l' = filter (\a -> a^.foo > 100) l 

The filter predicate looks a bit clumpsy. ((>100).(^.foo)) not much better. Without lenses, I would use ((>100) . foo) .

Is there a good way to create such predicates using lens ? Ideally, this would also allow predicates of the type (\a -> a^.foo > 100 && a^.bar < 50) .

+6
source share
1 answer

I think ((>100).(^.foo)) is probably the best you can do just using standard operators. If you want to define new comparison operators for lenses, you can do something like:

 import Control.Lens hiding ((.>)) import Control.Monad (liftM2) import Control.Monad.Reader (MonadReader) import Data.Function (on) (.==) :: (MonadReader sm, Eq a) => Getting Bool sa -> a -> m Bool (.==) l = views l . (==) infix 4 .== (.==.) :: (MonadReader sm, Eq a) => Getting asa -> Getting asa -> m Bool (.==.) = liftM2 (==) `on` view infix 4 .==. (.<) :: (MonadReader sm, Ord a) => Getting Bool sa -> a -> m Bool (.<) l = views l . flip (<) infix 4 .< (.<.) :: (MonadReader sm, Ord a) => Getting asa -> Getting asa -> m Bool (.<.) = liftM2 (<) `on` view infix 4 .<. (.<=) :: (MonadReader sm, Ord a) => Getting Bool sa -> a -> m Bool (.<=) l = views l . flip (<=) infix 4 .<= (.<=.) :: (MonadReader sm, Ord a) => Getting asa -> Getting asa -> m Bool (.<=.) = liftM2 (<=) `on` view infix 4 .<=. (.>) :: (MonadReader sm, Ord a) => Getting Bool sa -> a -> m Bool (.>) l = views l . flip (>) infix 4 .> (.>.) :: (MonadReader sm, Ord a) => Getting asa -> Getting asa -> m Bool (.>.) = liftM2 (>) `on` view infix 4 .>. (.>=) :: (MonadReader sm, Ord a) => Getting Bool sa -> a -> m Bool (.>=) l = views l . flip (>=) infix 4 .>= (.>=.) :: (MonadReader sm, Ord a) => Getting asa -> Getting asa -> 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 .||. 

The logic of operator selection is that the dot indicates the side that has the lens, so you can write either foo .== 5 or foo .==. bar foo .==. bar (where foo and bar are the lenses). Unfortunately, the lens package also defines its own operator (.<) , So maybe some other naming convention would be better. This was the first idea that came to my mind.

Using these new operators, you can write things like

 l' = filter (foo .> 100 .&&. bar .< 50) l 
+4
source

Source: https://habr.com/ru/post/944862/


All Articles