All and Any
This page is part of a series on Arithmetic Made Difficult.
This post is literate Haskell; you can load the source into GHCi and play along.
{-# LANGUAGE NoImplicitPrelude #-}
module AllAndAny
( all, any, _test_all_any, main_all_any
) where
import Testing
import Booleans
import Not
import And
import Or
import Predicates
import NaturalNumbers
import Lists
import Snoc
import Reverse
import Cat
import Map
Today we’ll define two boolean functions for lists called \all and \any. Each one takes as an argument a predicate A \rightarrow \bool, and then tests whether all or any of the items in a list of type \lists{A} satisfy the predicate.
Let A be a set and p : A \rightarrow \bool a predicate. Define \varphi : A \times \bool \rightarrow \bool by \varphi(a,q) = \band(p(a),q). Now define \all : \bool^A \rightarrow \bool^{\lists{A}} by \all(p)(x) = \foldr(\btrue)(\varphi)(x).
In Haskell:
Since \all(p) is defined as a \foldr(\ast)(\ast), it is the unique solution to a system of functional equations.
Let A be a set and p : A \rightarrow \bool a predicate. Then \all(p) is the unique solution f : \lists{A} \rightarrow \bool to the following equations for all a \in A and x \in \lists{A}. \left\{\begin{array}{l} f(\nil) = \btrue \\ f(\cons(a,x)) = \band(p(a),f(x)) \end{array}\right.
_test_all_nil :: (List t, Equal a)
=> t a -> Test ((a -> Bool) -> Bool)
_test_all_nil t =
testName "all(p)(nil) == true" $
\p -> all p (nil `withTypeOf` t)
_test_all_cons :: (List t, Equal a)
=> t a -> Test ((a -> Bool) -> a -> t a -> Bool)
_test_all_cons _ =
testName "all(p)(cons(a,x)) == and(p(a),all(p)(x))" $
\p a x -> eq (all p (cons a x)) (and (p a) (all p x))
\all interacts with \snoc.
Let A be a set. For all p : A \rightarrow \bool, a \in A, and x \in \lists{A}, we have \all(p,\snoc(a,x)) = \band(p(a),\all(p,x)).
We proceed by list induction on x. For the base case x = \nil, we have \begin{eqnarray*} & & \all(p,\snoc(a,x)) \\ & = & \all(p,\snoc(a,\nil)) \\ & \href{/posts/arithmetic-made-difficult/Snoc.html#cor-snoc-nil} = & \all(p,\cons(a,\nil)) \\ & = & \band(p(a),\all(p,\nil)) \\ & = & \band(p(a),\all(p,x)) \end{eqnarray*} as needed. For the inductive step, suppose the equality holds for all p and a for some x and let b \in A. Using the inductive step, we have \begin{eqnarray*} & & \all(p,\snoc(a,\cons(b,x))) \\ & \href{/posts/arithmetic-made-difficult/Snoc.html#cor-snoc-cons} = & \all(p,\cons(b,\snoc(a,x))) \\ & = & \band(p(b),\all(p,\snoc(a,x))) \\ & = & \band(p(b),\band(p(a),\all(p,x))) \\ & = & \band(p(a),\band(p(b),\all(p,x))) \\ & = & \band(p(a),\all(p,\cons(b,x))) \end{eqnarray*} as needed.
\all can also be characterized as a folded map.
\all(p,x) = \foldr(\btrue)(\band)(\map(p)(x)).
We proceed by list induction on x. For the base case x = \nil, we have \begin{eqnarray*} & & \all(p,x) \\ & = & \all(p,\nil) \\ & = & \btrue \\ & \href{/posts/arithmetic-made-difficult/Lists.html#def-foldr-nil} = & \foldr(\btrue)(\band)(\nil) \\ & = & \foldr(\btrue)(\band)(\map(p)(\nil)) \\ & = & \foldr(\btrue)(\band)(\map(p)(x)) \end{eqnarray*} as claimed. For the inductive step, suppose the equality holds for some x and let a \in A. Now \begin{eqnarray*} & & \all(p,\cons(a,x)) \\ & = & \band(p(a),\all(p,x)) \\ & = & \band(p(a),\foldr(\btrue)(\band)(\map(p)(x))) \\ & \href{/posts/arithmetic-made-difficult/Lists.html#def-foldr-cons} = & \foldr(\btrue)(\band)(\cons(p(a),\map(p)(x))) \\ & = & \foldr(\btrue)(\band)(\map(p)(\cons(a,x))) \end{eqnarray*} as needed.
Two special cases.
Let A be a set and p : A \rightarrow \bool a predicate. The following hold for all x \in \lists{A}.
- \all(\ptrue)(x) = \btrue.
- \all(\pfalse)(x) = \bfalse if and only if x \neq \nil.
- We proceed by list induction on x. For the base case x = \nil, we have \begin{eqnarray*} & & \all(\ptrue,x) \\ & = & \all(\ptrue,\nil) \\ & = & \btrue \end{eqnarray*} as claimed. For the inductive step, suppose the equality holds for some x and let a \in A. Now \begin{eqnarray*} & & \all(\ptrue)(\cons(a,x)) \\ & = & \band(\ptrue(a),\all(\ptrue)(x)) \\ & = & \band(\btrue,\btrue) \\ & \href{/posts/arithmetic-made-difficult/And.html#thm-and-eval-true-true} = & \btrue \end{eqnarray*} as claimed.
- We have two possibilities for x. If x = \nil, we have \begin{eqnarray*} & & \all(\pfalse)(\nil) \\ & = & \btrue, \end{eqnarray*} while if x = \cons(a,u), we have \begin{eqnarray*} & & \all(\pfalse)(\cons(a,u)) \\ & = & \band(\pfalse(a),\all(\pfalse)(u)) \\ & = & \band(\bfalse,\all(\pfalse)(u)) \\ & \href{/posts/arithmetic-made-difficult/And.html#thm-and-false-left} = & \bfalse \end{eqnarray*} as needed.
_test_all_const_true :: (List t, Equal a)
=> t a -> Test (t a -> Bool)
_test_all_const_true _ =
testName "all(ptrue)(x) == true" $
\x -> eq (all ptrue x) (true :: Bool)
_test_all_const_false :: (List t, Equal a, Equal (t a))
=> t a -> Test (t a -> Bool)
_test_all_const_false _ =
testName "all(pfalse)(x) == false iff x /= nil" $
\x -> eq
(eq (all pfalse x) (false :: Bool))
(not (eq x nil))
\all interacts with \cat.
Let A be a set and p : A \rightarrow \bool. For all x,y \in \lists{A} we have \all(p,\cat(x,y)) = \band(\all(p)(x),\all(p)(y)).
We proceed by list induction on x. For the base case x = \nil, we have \begin{eqnarray*} & & \all(p)(\cat(x,y)) \\ & = & \all(p)(\cat(\nil,y)) \\ & \href{/posts/arithmetic-made-difficult/Cat.html#cor-cat-nil} = & \all(p)(y) \\ & \href{/posts/arithmetic-made-difficult/And.html#thm-and-true-left} = & \band(\btrue,\all(p)(y)) \\ & = & \band(\all(p)(\nil),\all(p)(y)) \\ & = & \band(\all(p)(x),\all(p)(y)) \end{eqnarray*} as needed. For the inductive step, suppose the equality holds for some x and let a \in A. Now \begin{eqnarray*} & & \all(p)(\cat(\cons(a,x),y)) \\ & \href{/posts/arithmetic-made-difficult/Cat.html#cor-cat-cons} = & \all(p)(\cons(a,\cat(x,y))) \\ & = & \band(p(a),\all(p)(\cat(x,y))) \\ & = & \band(p(a),\band(\all(p)(x),\all(p)(y))) \\ & \href{/posts/arithmetic-made-difficult/And.html#thm-and-associative} = & \band(\band(p(a),\all(p)(x)),\all(p)(y)) \\ & = & \band(\all(p)(\cons(a,x)),\all(p)(y)) \end{eqnarray*} as needed.
\all interacts with \rev.
Let A be a set and p : A \rightarrow \bool. For all x \in \lists{A} we have \all(p,\rev(x)) = \all(p,x).
We proceed by list induction on x. For the base case x = \nil, we have \begin{eqnarray*} & & \all(p,\rev(x)) \\ & = & \all(p,\rev(\nil)) \\ & \href{/posts/arithmetic-made-difficult/Reverse.html#cor-rev-nil} = & \all(p,\nil) \\ & = & \all(p,x) \end{eqnarray*} as claimed. For the inductive step, suppose the equality holds for some x and let a \in A. Using the inductive hypothesis, we have \begin{eqnarray*} & & \all(p,\rev(\cons(a,x))) \\ & = & \all(p,\rev(\cat(\cons(a,\nil),x))) \\ & \href{/posts/arithmetic-made-difficult/Cat.html#thm-rev-cat-antidistribute} = & \all(p,\cat(\rev(x),\rev(\cons(a,\nil)))) \\ & = & \band(\all(p,\rev(x)),\all(p,\rev(\cons(a,\nil)))) \\ & = & \band(\all(p,x),\all(p,\cons(a,\nil))) \\ & \href{/posts/arithmetic-made-difficult/And.html#thm-and-commutative} = & \band(\all(p,\cons(a,\nil)),\all(p,x)) \\ & = & \all(p,\cat(\cons(a,\nil),x)) \\ & = & \all(p,\cons(a,x)) \end{eqnarray*} as claimed.
\all interacts with \pimpl.
Let A be a set and p,q : A \rightarrow \bool. If \pimpl(p,q), then \bimpl(\all(p,x),\all(q,x)).
We proceed by list induction on x. For the base case x = \nil, we have \begin{eqnarray*} & & \bimpl(\all(p,\nil),\all(q,\nil)) \\ & = & \bimpl(\btrue,\btrue) \\ & \href{/posts/arithmetic-made-difficult/Implies.html#thm-implies-true-hyp} = & \btrue \end{eqnarray*} as needed. For the inductive step, suppose the implication holds for some x and let a \in A. Now \bimpl(p(a),q(a)), and by the induction hypothesis \bimpl(\all(p,x),\all(q,x)). Then we have \begin{eqnarray*} & & \bimpl(\all(p,\cons(a,x)),\all(q,\cons(a,x))) \\ & = & \bimpl(\band(p(a),\all(p,x)),\band(q(a),\all(q),x)) \\ & = & \btrue \end{eqnarray*} as needed.
\all interacts with \map.
Let A and B be sets with f : A \rightarrow B and p : B \rightarrow \bool. Then for all x \in \lists{A} we have \all(p)(\map(f)(x)) = \all(p \circ f)(x).
We proceed by list induction on x. For the base case x = \nil, we have \begin{eqnarray*} & & \all(p)(\map(f)(x)) \\ & = & \all(p)(\map(f)(\nil)) \\ & \href{/posts/arithmetic-made-difficult/Map.html#cor-map-nil} = & \all(p)(\nil) \\ & = & \btrue \\ & = & \all(p \circ f)(\nil) \\ & = & \all(p \circ f)(x) \end{eqnarray*} as needed. For the inductive step, suppose the equality holds for some x and let a \in A. Now \begin{eqnarray*} & & \all(p)(\map(f)(\cons(a,x))) \\ & \href{/posts/arithmetic-made-difficult/Map.html#cor-map-cons} = & \all(p)(\cons(f(a),\map(f)(x))) \\ & = & \band(p(f(a)),\all(p)(\map(f)(x))) \\ & = & \band((p \circ f)(a),\all(p \circ f)(x)) \\ & = & \all(p \circ f)(\cons(a,x)) \end{eqnarray*} as needed.
\any is defined similarly.
Let A be a set and p : A \rightarrow \bool a predicate. Define \varphi : A \times \bool \rightarrow \bool by \varphi(a,q) = \bor(p(a),q). Now define \any : \bool^A \rightarrow \bool^{\lists{A}} by \all(p)(x) = \foldr(\bfalse)(\varphi)(x).
In Haskell:
Since \any is defined as a fold, it is the unique solution to a system of functional equations.
Let A be a set and p a predicate on A. \any(p) is the unique map f : \lists{A} \rightarrow \bool satisfying the following equations for all a \in A and x \in \lists{A}. \left\{\begin{array}{l} f(\nil) = \bfalse \\ f(\cons(a,x)) = \bor(p(a),f(x)) \end{array}\right.
_test_any_nil :: (List t, Equal a)
=> t a -> Test ((a -> Bool) -> Bool)
_test_any_nil t =
testName "any(p)(nil) == false" $
\p -> eq (any p (nil `withTypeOf` t)) false
_test_any_cons :: (List t, Equal a)
=> t a -> Test ((a -> Bool) -> a -> t a -> Bool)
_test_any_cons _ =
testName "any(p)(cons(a,x)) == or(p(a),any(p)(x))" $
\p a x -> eq (any p (cons a x)) (or (p a) (any p x))
\any can also be characterized as a folded map.
Let A be a set with p a predicate on A. Then \any(p,x) = \foldr(\bfalse)(\bor)(\map(p)(x)).
We proceed by list induction on x. For the base case x = \nil, we have \begin{eqnarray*} & & \any(p,x) \\ & = & \any(p,\nil) \\ & = & \bfalse \\ & \href{/posts/arithmetic-made-difficult/Lists.html#def-foldr-nil} = & \foldr(\bfalse)(\bor)(\nil) \\ & = & \foldr(\bfalse)(\bor)(\map(p)(\nil)) \\ & = & \foldr(\bfalse)(\bor)(\map(p)(x)) \end{eqnarray*} as needed. For the inductive step, suppose the equality holds for some x and let a \in A. Then we have \begin{eqnarray*} & & \any(p,\cons(a,x)) \\ & = & \bor(p(a),\any(x)) \\ & = & \bor(p(a),\foldr(\bfalse)(\bor)(\map(p)(x))) \\ & \href{/posts/arithmetic-made-difficult/Lists.html#def-foldr-cons} = & \foldr(\bfalse)(\bor)(\cons(p(a),\map(p)(x))) \\ & = & \foldr(\bfalse)(\bor)(\map(p)(\cons(a,x))) \end{eqnarray*} as needed.
A version of DeMorgan’s law holds for \any and \all.
Let A be a set with p : A \rightarrow \bool. Then the following hold for all x \in \lists{A}.
- \any(p,x) = \bnot(\all(\bnot \circ p,x)).
- \all(p,x) = \bnot(\any(\bnot \circ p,x)).
- We proceed by list induction on x. For the base case x = \nil, we have \begin{eqnarray*} & & \bnot(\all(\bnot \circ p,x)) \\ & = & \bnot(\all(\bnot \circ p,\nil)) \\ & = & \bnot(\btrue) \\ & \href{/posts/arithmetic-made-difficult/Not.html#thm-not-true} = & \bfalse \\ & = & \foldr(\bfalse)(\varphi(p))(\nil) \\ & = & \foldr(\bfalse)(\varphi(p))(x) \end{eqnarray*} as needed. For the inductive step, suppose the equality holds for some x and let a \in A. Then we have \begin{eqnarray*} & & \bnot(\all(\bnot \circ p,\cons(a,x))) \\ & = & \bnot(\band(\bnot(p(a)),\all(\bnot \circ p,x))) \\ & = & \bor(\bnot(\bnot(p(a))),\bnot(\all(\bnot \circ p,x))) \\ & = & \bor(p(a),\any(p,x)) \\ & = & \any(p,\cons(a,x)) \end{eqnarray*} as needed.
- Note that \begin{eqnarray*} & & \bnot(\any(\bnot \circ p,x)) \\ & = & \bnot(\bnot(\all(\bnot \circ \bnot \circ p,x))) \\ & = & \all(p,x) \end{eqnarray*} as claimed.
_test_any_not_all :: (List t, Equal a)
=> t a -> Test ((a -> Bool) -> t a -> Bool)
_test_any_not_all _ =
testName "any(p,x) == not(all(not . p, x))" $
\p x -> eq (any p x) (not (all (not . p) x))
_test_all_not_any :: (List t, Equal a)
=> t a -> Test ((a -> Bool) -> t a -> Bool)
_test_all_not_any _ =
testName "all(p,x) == not(any(not . p, x))" $
\p x -> eq (all p x) (not (any (not . p) x))
Two special cases.
Let A be a set and p : A \rightarrow \bool a predicate. The following hold for all x \in \lists{A}.
- \any(\pfalse)(x) = \bfalse.
- \any(\ptrue)(x) = \btrue if and only if x \neq \nil.
- Note that \begin{eqnarray*} & & \any(\pfalse)(x) \\ & = & \bnot(\all(\bnot \circ \pfalse)(x)) \\ & = & \bnot(\all(\ptrue)(x)) \\ & = & \bnot(\btrue) \\ & \href{/posts/arithmetic-made-difficult/Not.html#thm-not-true} = & \bfalse \end{eqnarray*} as claimed.
- If x = \nil, we have \begin{eqnarray*} & & \any(\pfalse)(x) \\ & = & \btrue, \end{eqnarray*} while if x = \cons(a,u) we have \begin{eqnarray*} & & \any(\ptrue)(\cons(a,u)) \\ & = & \bnot(\all(\bnot \circ \ptrue)(\cons(a,u))) \\ & = & \bnot(\all(\pfalse)(\cons(a,u))) \\ & = & \bnot(\bfalse) \\ & \href{/posts/arithmetic-made-difficult/Not.html#thm-not-false} = & \btrue \end{eqnarray*} as needed.
_test_any_const_false :: (List t, Equal a)
=> t a -> Test (t a -> Bool)
_test_any_const_false _ =
testName "any(pfalse,x) == false" $
\x -> eq (any pfalse x) (false :: Bool)
_test_any_const_true :: (List t, Equal a, Equal (t a))
=> t a -> Test (t a -> Bool)
_test_any_const_true _ =
testName "any(ptrue,x) == true iff x /= nil" $
\x -> eq
(eq (any ptrue x) (true :: Bool))
(not (eq x nil))
\any interacts with \cat.
Let A be a set and p : A \rightarrow \bool. For all x,y \in \lists{A} we have \any(p,\cat(x,y)) = \bor(\any(p)(x),\any(p)(y)).
Note that \begin{eqnarray*} & & \any(p,\cat(x,y)) \\ & = & \bnot(\all(\bnot \circ p,\cat(x,y))) \\ & = & \bnot(\band(\all(\bnot \circ p,x),\all(\bnot \circ p,y))) \\ & = & \bor(\bnot(\all(\bnot \circ p,x)),\bnot(\all(\bnot \circ p,y))) \\ & = & \bor(\any(p,x),\any(p,y)) \end{eqnarray*} as claimed.
\any interacts with \rev.
Let A be a set and p : A \rightarrow \bool. For all x,y \in \lists{A} we have \any(p,\rev(x)) = \any(p,x).
Note that \begin{eqnarray*} & & \any(p,\rev(x)) \\ & = & \bnot(\all(\bnot \circ p,\rev(x))) \\ & = & \bnot(\all(\bnot \circ p,x)) \\ & = & \any(p,x) \end{eqnarray*} as claimed.
\any interacts with \map.
Let A and B be sets with f : A \rightarrow B and p : B \rightarrow \bool. Then for all x \in \lists{A} we have \any(p)(\map(f)(x)) = \any(p \circ f)(x).
Note that \begin{eqnarray*} & & \any(p,\map(f)(x)) \\ & = & \bnot(\all(\bnot \circ p,\map(f)(x))) \\ & = & \bnot(\all((\bnot \circ p) \circ f,x)) \\ & = & \bnot(\all(\bnot \circ (p \circ f),x)) \\ & = & \any(p \circ f,x) \end{eqnarray*} as claimed.
Testing
Suite:
_test_all_any ::
( TypeName a, Show a, Equal a, Arbitrary a, CoArbitrary a
, TypeName (t a), List t
, Show (t a), Equal (t a), Arbitrary (t a)
) => Int -> Int -> t a -> IO ()
_test_all_any size cases t = do
testLabel1 "all & any" t
let args = testArgs size cases
runTest args (_test_all_nil t)
runTest args (_test_all_cons t)
runTest args (_test_all_snoc t)
runTest args (_test_all_fold_and t)
runTest args (_test_all_const_true t)
runTest args (_test_all_const_false t)
runTest args (_test_all_cat t)
runTest args (_test_all_rev t)
runTest args (_test_all_map t)
runTest args (_test_any_nil t)
runTest args (_test_any_cons t)
runTest args (_test_any_fold_or t)
runTest args (_test_any_not_all t)
runTest args (_test_all_not_any t)
runTest args (_test_all_const_false t)
runTest args (_test_all_const_true t)
runTest args (_test_any_cat t)
runTest args (_test_any_rev t)
runTest args (_test_any_map t)
Main: