Haskell lens getter that compares values of two lens getters

137 Views Asked by At

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?

1

There are 1 best solutions below

0
On BEST ANSWER

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.)