Skip to content

and and or

If we have a container of Bools, we can ask whether all its elements are True or at least one element is True. That's and and or:

and, or :: Foldable t => t Bool -> Bool
and = getAll . foldMap All
or  = getAny . foldMap Any

This uses the fact that Booleans with logical and or logical or as the multiplication operation form a monoid. The unit for the and-monoid is True. The unit for the or-monoid is False. The only problem is that when declaring a type to be a monoid in Haskell, we need to commit to one operation, here and or or. This is one limitation of type classes in Haskell that has been the subject of extensive debate and the focus of some effort to find more flexible solutions. The way to work around this limitation is to wrap the Bool type into newtypes. The first newtype, Any, is essentially Bool with or as the monoid multiplication. All is Bool with and as the monoid multiplication:

newtype Any = Any { getAny :: Bool }
newtype All = All { getAll :: Bool }

instance Semigroup Any where
    Any x <> Any y = Any (x || y)

instance Semigroup All where
    All x <> All y = All (x && y)

instance Monoid Any where
    mempty = Any False

instance Monoid All where
    mempty = All True

This is the same trick we used to define monoids over number types that used addition or multiplication as the monoid operations. Those were our Sum and Product monoids.

Here are and and or in action:

GHCi
>>> and [True,False,True,True]
False
>>> and [True,True,True,True]
True
>>> or [True,False,False,False]
True
>>> or [False,False,False,False]
False