-1

I'm trying to create a function definition for the function all using foldr. p is the predicate. I know this can be done:

all p = and . foldr (\x xs -> p x : xs) []

But what I want to do is to shift the function and into the foldr equation. Can this be done?

I've tried the following, which all failed to work:

all p = foldr (\x p -> \ys -> and (p x) ys) True
all p = foldr (\x and -> (\ys -> (p x and ys))) True
all p = foldr (\x ys -> and . (p x) ys) True

Am I falling short in my understanding of how to apply foldr?

Will Ness
  • 70,110
  • 9
  • 98
  • 181
maxloo
  • 453
  • 2
  • 12
  • 3
    It kinda looks like you're trying to _guess_ the correct version by randomly shuffling the words around. For example, what do you think `p x and ys` would mean? – Fyodor Soikin Jul 11 '20 at 16:28
  • Hint: `all p = and . map p` Note that `and` is outside the `map`. – Joseph Sible-Reinstate Monica Jul 11 '20 at 16:29
  • @Fyodor: actually `and (p x) ys` is something I understand, which is equivalent to `(p x) && ys`. I do not quite understand `p x and ys`. It's not supposed to work unless I use backticks on `and`. Somehow in foldr, I have to use `(&&)` and not simply `&&`. This is something I do not understand too.. – maxloo Jul 11 '20 at 16:35
  • whether to use `&&` or `(&&)` is a matter of syntax, choosing what's appropriate in a given situation. – Will Ness Jul 11 '20 at 16:37
  • `and` works with lists, `(&&)` works with two arguments in the prefix position, or `&&` in infix. – Will Ness Jul 11 '20 at 16:37
  • could the dv'ers please explain their reasons? – Will Ness Jul 11 '20 at 16:39
  • @Joseph: I understand that `and` is outside `map`. I'm trying to shift `and` into the `foldr` function for `map`. That's how I got my first equation: `all p = and . foldr (\x xs -> p x : xs) []` – maxloo Jul 11 '20 at 16:39
  • You can't use `and` inside the `foldr`, because it does the wrong thing. Replace `and` with its definition and then fuse that into your `foldr`. – Joseph Sible-Reinstate Monica Jul 11 '20 at 16:40
  • @Will: Thanks, that's a good reminder, but I'm nowhere near a solution to my problem.. – maxloo Jul 11 '20 at 16:43
  • @Joseph: well, I've tried `all p = foldr (\x p -> \ys -> (&&) (p x) ys) True` before and it doesn't work. In fact, I've tried both `and` and `(&&)`, and both don't work.. the error goes, Type: b -> (b -> Bool) -> Bool -> Bool, Does not match : a -> Bool -> Bool – maxloo Jul 11 '20 at 17:00
  • That's because that's the wrong way to fuse them. The answer from Will Ness shows you the right way. – Joseph Sible-Reinstate Monica Jul 11 '20 at 17:03
  • @Joseph: It is precisely all these type definitions that come out during errors that confuse me when I'm using `foldr`. – maxloo Jul 11 '20 at 17:06

1 Answers1

5

We have

all p = and 
         . foldr (\x xs -> p x :  xs) []    
      = foldr                 (&&)   True   -- {y : ys} -> y && {ys}      2-3
         . foldr (\x xs -> p x :  xs) []    -- {x , xs} -> p x : {xs}   1-2
      =    foldr (\x xs -> p x && xs) True  -- {x , xs} -> p x && {xs}  1---3

because folding replaces each constructor with the specified combination operation (aka reducer), and replacing a cons of an element with a cons of a modified element, and then replacing that cons with (&&), is just replacing a cons of an element with the (&&) of a modified element right away:

    a  : (  b  : (  c  : (  d  : ( ... ))))   _OR_   []      --   |       |   1
                                                             --   |       |
  p a  : (p b  : (p c  : (p d  : ( ... ))))   _OR_   []      --   ↓   |   |   2
                                                             --       |   |
  p a && (p b && (p c && (p d && ( ... ))))   _OR_  True     --       ↓   ↓   3

In other words, folds compose by fusing their reducer functions, and reducer functions fuse by replacing the {constructors they use} with the next fold's reducer in the chain of folds, so that their corresponding transducers compose (as in Clojure's transducers); thus,

 = foldr              (reducingWith (&&)) True
     . foldr ((mapping p)    (:))           []
 = foldr ((mapping p) (reducingWith (&&))) True
 = foldr ((mapping p . reducingWith) (&&) ) True
   -- first map p, then reduce with (&&)

for the appropriate definitions of reducingWith and mapping:

reducingWith cons x xs = cons x xs
mapping f cons x xs = cons (f x) xs
filtering p cons x xs | p x = cons x xs
                      | otherwise = xs
concatting t cons x xs = foldr cons xs (t x)
Will Ness
  • 70,110
  • 9
  • 98
  • 181
  • Thanks! But I still have questions because I have not learnt reducer functions. How does foldr know that `xs` from `p x : xs` is a list if we replace the cons and the equation becomes `p x && xs`? `&&` only applies to arguments right? – maxloo Jul 11 '20 at 17:25
  • Thanks, I think I understand. `Foldr` always works with lists, so the right associativity related to it is inbuilt. There is no need to indicate a list by `x : xs`. The cons can just simply be replaced. – maxloo Jul 11 '20 at 17:48
  • I do not fully understand your explanation at `p a : (p b : (p c : (p d : ( ... )))) -OR- [] v | |`. What do you mean by `v` and `|`? – maxloo Jul 11 '20 at 17:51
  • that was my attempt as drawing vertical arrows using ASCII. those are supposed to be the arrows going from the 1st row to the 2nd, and from the 2nd to the 3rd; and the composed arrows goes from the 1st row to the 3rd, corresponding to the fused fold. the `-OR- X` means that it's `X` in case the list `[a,b,c,d,...]` was actually an empty list, `[]`. – Will Ness Jul 11 '20 at 21:29
  • Thanks! You may be able to help with a new question of mine: https://stackoverflow.com/questions/63547939/haskell-how-to-create-a-maptree-function-based-on-a-foldr-of-a-binarytree – maxloo Aug 23 '20 at 14:20
  • @maxloo do consider *accepting* the most helpful answer to signal that your issue is resolved here. it *is* resolved, isn't it? – Will Ness Aug 23 '20 at 14:30
  • yes, I've just accepted your answer. Thanks again! – maxloo Aug 23 '20 at 15:37