How can I redefine the all
function in haskell using foldr
?
I tried writing it like this and I'm not sure why it doesn't work.
all :: (a -> Bool) -> [a] -> Bool
all p (x:xs) = foldr (&&) True ((p x) : (all p xs))
How can I redefine the all
function in haskell using foldr
?
I tried writing it like this and I'm not sure why it doesn't work.
all :: (a -> Bool) -> [a] -> Bool
all p (x:xs) = foldr (&&) True ((p x) : (all p xs))
You are mixing the foldr
and the function being defined with it. You're defining all
with foldr
, not with all
. foldr
captures the recursion pattern, it replaces the explicit recursion.
What you need is
all p xs = foldr (&&) True (map p xs)
= foldr ((&&) . p) True xs
because
all p [ x, y ] =
all p ( x : y : [] ) =
= p x && (p y && True )
= ((&&) . p) x ( ((&&) . p) y True )
because that's what foldr g z xs
is: it replaces :
in xs
with g
, and []
with z
, turning e.g. [x, y] = (x : y : [])
into x `g` (y `g` z) = g x (g y z)
.
We also use
(f . g) x = f (g x)
by definition (.
is called "function composition operator"), and
(&&) p q = p && q
because in Haskell, enclosing an infix operator in parentheses lets us treat is as a function.
I think you misunderstand how foldr
works. The idea is that, for a list, foldr
replaces (:)
with the folding function. This thus means that the second parameter of the fold function already is the result of folding the rest of the list.
This thus means that for:
all' :: Foldable f => (a -> Bool) -> f a -> Bool
all' p xs = foldr f True xs
where f = …
f
takes two parameters: an element of the list, and the foldr f True
on the rest of the list. You thus can assume that the second parameter is already the all'
function called on the rest of the list.
We thus can call p
on the element x
, and then calculate the logical and with the all'
of the rest of the list, so:
all' :: Foldable f => (a -> Bool) -> f a -> Bool
all' p xs = foldr f True xs
where f x as = p x && as
so here x
is the head element of the list, and as
is the all'
called on the rest of the list.
We can rewrite f x as = p x && as
to f x = (p x &&)
, or even point-free with f = (&&) . p
, so then we can rewrite all'
to:
all' :: Foldable f => (a -> Bool) -> f a -> Bool
all' p = foldr ((&&) . p) True
or even make all'
point-free with:
all' :: Foldable f => (a -> Bool) -> f a -> Bool
all' = flip foldr True . ((&&) .)