2

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))
Will Ness
  • 70,110
  • 9
  • 98
  • 181
AndreeaC26
  • 21
  • 1
  • 1
    I think, the problem is that you're mixing `foldr` and recursion. It's enough to write `all p x = foldr (&&) True $ map p x`. – bereal Nov 22 '20 at 10:29
  • 1
    You should not call `all p xs`, `foldr` itself is a way to define recursion on a list. – Willem Van Onsem Nov 22 '20 at 10:36
  • 1
    Does this answer your question? [Haskell - creating a function definition for the function \`all\` using foldr](https://stackoverflow.com/questions/62851579/haskell-creating-a-function-definition-for-the-function-all-using-foldr) – Eggcellentos Nov 22 '20 at 11:12

2 Answers2

3

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.

Will Ness
  • 70,110
  • 9
  • 98
  • 181
3

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 . ((&&) .)
Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555