internalAnd :: Bool -> Bool -> Bool
internalAnd True True = True
internalAnd _ _ = False
(&&) :: Applicative m => m Bool -> m Bool -> m Bool
(&&) = liftA2 internalAnd
-- Usage
greaterThan x = (x <)
lessThan x = (x >)
validateAge = greaterThan 0 && lessThan 120 -- It's really useful with combinators.
I think it is useful to define all functions over Applicative
for many situation like making combinators. And applicative is abstraction of applicability that is corresponding to function's ability, so it seems not bad to do like this.
What is expected problems of defining all the functions over Applicative
?
CodePudding user response:
One disadvantage is that you now cannot use it for normal booleans anymore. So, you'd have to write pure True && pure False
instead of True && False
. And if you want to get at the result you'd have to use runIdentity :: Identity a -> a
or something like that.
A more subtle problem is that your proposed function is less lazy. Usually, programmers expect &&
to be short-circuiting. So it should still return False
if you write False && undefined
, but your function will get stuck if you write pure False && undefined
. Really you'd want to implement it as a monad:
(&&) :: Monad m => m Bool -> m Bool -> m Bool
x && y = do
x' <- x
if x
then y
else pure False
A common alternative is to give it another name, e.g. <&&>
.