Search code examples
haskellhaskell-lenslenses

Haskell lens getter that compares values of two lens getters


I try to write a comparison operator greater-than-equals for two lens getters with type

(.>=.) :: Ord a => Getting a s a -> Getting a s a -> Getting Bool s Bool

I have a working solution for a getter on the left side and a value on the right side (no . on the right side of the operator .>=)

left .>= right = left . to (>= right)

I tried

left .>=. right = (>=) <$> use left <*> use right

but it has type

(.>=.) :: (Ord a, MonadState s f) => Getting a s a -> Getting a s a -> f Bool

How can I get the desired return type Getting Bool s Bool instead of f Bool?


Solution

  • You're close with this:

    λ> left .>=. right = (>=) <$> use left <*> use right
    (.>=.) ::
      (Ord a, Control.Monad.State.Class.MonadState s f) =>
      Getting a s a -> Getting a s a -> f Bool
    

    First, use view in instead of use; use is for getting from state (hence the MonadState constraint), which doesn't seem relevant here.

    λ> left .>=. right = (>=) <$> view left <*> view right
    (.>=.) ::
      (Ord a, Control.Monad.Reader.Class.MonadReader s f) =>
      Getting a s a -> Getting a s a -> f Bool
    

    That gives you a function (MonadReader s f => f Bool specializes to s -> Bool), so now you need to turn this into a Getting with to.

    λ> left .>=. right = to $ (>=) <$> view left <*> view right
    (.>=.) ::
      (Ord a, Contravariant f, Profunctor p) =>
      Getting a s a -> Getting a s a -> Optic' p f s Bool
    

    (And (Contravariant f, Profunctor p) => Optic' p f s Bool specializes to Getting Bool s Bool, so this is what you want.)