X.ManageHook: Make (<&&>) and (<||>) lazy in their second argument

While an implementation of `liftM2 (&&)` may seem like a straightforward
lift of `(&&)` into a monadic setting, it actually expands to

    (<&&>) :: Monad m => m Bool -> m Bool -> m Bool
    mb <&&> mb' = do
      a <- mb
      b <- mb'
      return (a && b)

which runs both monadic effects first and then applies `(&&)`.

This is fixed by introducing a monadic version of `if-then-else` (which
is also exported due to its usefulness) that checks the second result
only if this is explicitly necessary.
This commit is contained in:
slotThe
2021-10-16 16:07:34 +02:00
parent 33a86c0cdb
commit d92125485a

View File

@@ -61,11 +61,15 @@ infixr 3 <&&>, <||>
-- | '&&' lifted to a 'Monad'.
(<&&>) :: Monad m => m Bool -> m Bool -> m Bool
(<&&>) = liftM2 (&&)
(<&&>) x y = ifM x y (pure False)
-- | '||' lifted to a 'Monad'.
(<||>) :: Monad m => m Bool -> m Bool -> m Bool
(<||>) = liftM2 (||)
(<||>) x y = ifM x (pure True) y
-- | If-then-else lifted to a 'Monad'.
ifM :: Monad m => m Bool -> m a -> m a -> m a
ifM mb t f = mb >>= \b -> if b then t else f
-- | Return the window title.
title :: Query String