If you want to fold a list, I see four ways to do it.
Fold from the right of the list, with the recursive term on the right
foldrr (-) 100 [1..10] = 1 - (2 - (3 - (4 - (5 - (6 - (7 - (8 - (9 - (10 - (100)))))))))) = 95
foldrr :: (a -> b -> b) -> b -> [a] -> b
foldrr step zero (x:xs) = step x (foldrr step zero xs)
foldrr _ zero [] = zero
Fold from the right of the list, with the recursive term on the left
foldrl (-) 100 [1..10] = ((((((((((100) - 10) - 9) - 8) - 7) - 6) - 5) - 4) - 3) - 2) - 1 = 45
foldrl :: (a -> b -> a) -> a -> [b] -> a
foldrl step zero (x:xs) = step (foldrl step zero xs) x
foldrl _ zero [] = zero
Fold from the left of the list with the recursive term on the right
foldlr (-) 100 [1..10] = 10 - (9 - (8 - (7 - (6 - (5 - (4 - (3 - (2 - (1 - (100)))))))))) = 105
foldlr :: (a -> b -> b) -> b -> [a] -> b
foldlr step zero (x:xs) = foldlr step (step x zero) xs
foldlr _ zero [] = zero
Fold from the left of the list with the recursive term on the left
foldll (-) 100 [1..10] = ((((((((((100) - 1) - 2) - 3) - 4) - 5) - 6) - 7) - 8) - 9) - 10 = 45
foldll :: (a -> b -> a) -> a -> [b] -> a
foldll step zero (x:xs) = foldll step (step zero x) xs
foldll _ zero [] = zero
Only two of these folds made it into Prelude as foldr and foldl. Was there any reason to just include two folds, and why those two?
foldrl and foldlr don't add any expressive power: they are just the same as the other two folds but with the folding function flipped.
foldrl f = foldr (flip f)
foldlr f = foldl (flip f)
-- Or this, if you prefer
foldrl = foldr . flip
foldlr = foldl . flip
But it is not so easy to define foldl in terms of foldr, so providing them both is useful.
Related
Here an example to illustrate what I mean
Prelude> foldr (-) 0 [0,1]
-1
I thought here it would basically do 0 - 0 = 0; 1 - 0 = 1; but the actual result is -1
I tried it with other examples
Prelude> foldr (-) 1 [1,3]
-1
Prelude> foldr (-) 1 [1,9]
-7
I probably misunderstood how foldr works so I would be happy about an explanation :)
Consider the following function:
printfoldr f init xs = foldr (\el acc -> "(" ++ el ++ f ++ acc ++ ")") (show init) $ map show xs
This function simulates how the foldr function expands and outputs its string representation.
Let's run a few tests:
λ> printfoldr "-" 0 [1,2,3,4]
"(1-(2-(3-(4-0))))"
-- the test cases you provided
λ> printfoldr "-" 0 [1,2]
"(1-(2-0))" -- This reduces to -1 which is the result you had
λ> printfoldr "-" 1 [1,3]
"(1-(3-1))" -- This reduces to -1 which is also the result you had
λ> printfoldr "-" 1 [1,9]
"(1-(9-1))" -- reduces -7 which is also correct
So in general, foldr with type foldr :: (a -> b -> b) -> b -> t a -> b works as follows:
x0 `f` (x1 `f` ...(xn-2 `f` (xn-1 `f` (xn `f` init))))
where f is of type (a -> b -> b), x is of type a and init is of type b.
Try foldr (-) 0 [1, 2, 3, 4, 5]. You should get 3. That's because the fold is equivalent to (1 - (2 - (3 - (4 - (5 - 0))))) -- it's starting from the right. If you try foldl, you should get -15. That's because it's starting from the left and is equivalent to (((((0 - 1) - 2) - 3) - 4) - 5).
Your shorter example, foldr (-) 0 [0, 1], is equivalent to 0 - (1 - 0), which reduces to -1.
foldr is defined as follows:
foldr f b [] = b
foldr f b (x:xs) = f x (foldr f b xs)
You recursively fold the tail of the list, then apply f to the head and the recursive result. Note that the base value is used at the end of the sequence, not the beginning.
Thinking of it as simply applying the function to one value after another only works if f is associative. For example, 1 + (2 + (3 + 0)) == ((1+2) + 3) + 0.
Subtraction, though, is not associative. In general, x - y - z is only equal to (x - y) - z, not x - (y - z).
I have written the following Haskell code to return the primary and secondary diagonal of [[Int]]
getDiagonal' :: [[Int]] -> Int -> (Int -> Int) -> [Int]
getDiagonal' [] _ _ = []
getDiagonal' (x:xs) i fn = i' : getDiagonal' xs (fn i) fn
where i' = head $ drop i x
getPrimaryDiagonal :: [[Int]] -> [Int]
getPrimaryDiagonal x = getDiagonal' x 0 (+1)
getSecondaryDiagonal :: [[Int]] -> [Int]
getSecondaryDiagonal x = getDiagonal' x ((length x) - 1) (+(-1))
However, I would have thought that the final line could be the following, using (-) the same way as (+)
getSecondaryDiagonal x = getDiagonal' x ((length x) - 1) (-1)
However, that does not work, when I do that I get
Main.hs:27:59: error:
• No instance for (Num (Int -> Int))
arising from a use of syntactic negation
(maybe you haven't applied a function to enough arguments?)
• In the third argument of ‘getDiagonal'’, namely ‘(- 1)’
In the expression: getDiagonal' x ((length x) - 1) (- 1)
In an equation for ‘getSecondaryDiagonal’:
getSecondaryDiagonal x = getDiagonal' x ((length x) - 1) (- 1)
Why does (-) produce that error?
(-1) is interpreted as negative one, it is, as far as I know, the only exception that is made for operators that are non-binary. (-1) is thus not a function that subtracts one away.
You can make use of subtract :: Num a => a -> a -> a for this:
getSecondaryDiagonal x = getDiagonal' x ((length x) - 1) (subtract 1)
or you can use flip :: (a -> b -> c) -> b -> a -> c which is how subtract is implemented:
getSecondaryDiagonal x = getDiagonal' x ((length x) - 1) (flip (-) 1)
This question already has an answer here:
Haskell foldr with function
(1 answer)
Closed 5 years ago.
I just have a question about the usage of foldr.
Say I want to use foldr in this way:
foldr (\x y -> (x + y)/2) 2 [4,5,6]
Is y in this case represents each element of the list?
In particular, let's unwrap this function.
we have (x = 2, y= 6) -> (2+6)/2 = 4.
Next, do we have x=4, y = 5?
I am asking a simplify version of what I really want to ask. Here, the content of x and y represents matter a lot because in my application, I have a function that takes 1st argument as type a, and second argument as type b. Thus, I do need to know whats going on under-the hood.
Say I want to use foldr in this way:
foldr (\x y -> (x + y)/2) 2 [4,5,6]
Is y in this case represents each element of the list?
One way of figuring it out is looking at the type of foldr:
GHCi> :t foldr
foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b
The structure being folded has type t a for some Foldable t (in your case, you have a list, and so t is []), and its elements have type a. The result accumulated through the fold has type b. The binary function used for folding has type a -> b -> b, so the elements are passed as its first argument, and the accumulated value, as its second.
Another way of figuring out is by reading the actual implementation of foldr for lists (I found this by looking for the Foldable instance of lists and then following the source links). You might want to try that, to see how one picture corresponds to the other.
foldr f startingValue (x:xs) expands to f x (foldr f startingValue xs), and foldr f startingValue [] expands to startingValue so in your case:
foldr (\x y -> (x + y)/2) 2 [4,5,6]
(\x y -> (x + y)/2) 4 (foldr (\x y -> (x + y)/2) 2 [5,6])
(\x y -> (x + y)/2) 4 ((\x y -> (x + y)/2) 5 (foldr (\x y -> (x + y)/2) 2 [6]))
(\x y -> (x + y)/2) 4 ((\x y -> (x + y)/2) 5 ((\x y -> (x + y)/2) 6 (foldr (\x y -> (x + y)/2) 2 [])))
(\x y -> (x + y)/2) 4 ((\x y -> (x + y)/2) 5 ((\x y -> (x + y)/2) 6 2))
(\x y -> (x + y)/2) 4 ((\x y -> (x + y)/2) 5 4)
(\x y -> (x + y)/2) 4 4.5
4.25
It might be easier to see with f x y = (x + y)/2:
foldr f 2 [4,5,6]
f 4 (foldr f 2 [5,6])
f 4 (f 5 (foldr f 2 [6]))
f 4 (f 5 (f 6 (foldr f 2 [])))
f 4 (f 5 (f 6 2))
f 4 (f 5 4)
f 4 4.5
4.25
If you understand how cons lists are constructed (using :), you can think of foldr as replacing all the : with the function you provide.
For instance, I want to extract from a list the numbers that end in 67: 1637767, 9967, 523467...
Compare them modulo 100:
let result = filter ((== 67) . (`mod` 100)) numbers
The other answers will work if all you want is to match a 2-digit number. Here is a more generalized solution:
import Data.List (isSuffixOf)
extractSuff :: Int -> [Int] -> [Int]
extractSuff n xs = filter (\x -> isSuffixOf (show n) (show x)) xs
EDIT:
Upon Guvante's suggestion, I'm adding another solution which doesn't stringify numbers.
extractSuff' :: Int -> [Int] -> [Int]
extractSuff' n xs = filter (\x -> n == (x `mod` (10 ^ (numDigits n)))) xs
where numDigits n
| abs n < 10 = 1
| otherwise = 1 + numDigits (n `div` 10)
I've been trying to wrap my head around foldr and foldl for quite some time, and I've decided the following question should settle it for me. Suppose you pass the following list [1,2,3] into the following four functions:
a = foldl (\xs y -> 10*xs -y) 0
b = foldl (\xs y -> y - 10 * xs) 0
c = foldr (\y xs -> y - 10 * xs) 0
d = foldr (\y xs -> 10 * xs -y) 0
The results will be -123, 83, 281, and -321 respectively.
Why is this the case? I know that when you pass [1,2,3,4] into a function defined as
f = foldl (xs x -> xs ++ [f x]) []
it gets expanded to ((([] ++ [1]) ++ [2]) ++ [3]) ++ [4]
In the same vein, What do the above functions a, b, c, and d get expanded to?
I think the two images on Haskell Wiki's fold page explain it quite nicely.
Since your operations are not commutative, the results of foldr and foldl will not be the same, whereas in a commutative operation they would:
Prelude> foldl1 (*) [1..3]
6
Prelude> foldr1 (*) [1..3]
6
Using scanl and scanr to get a list including the intermediate results is a good way to see what happens:
Prelude> scanl1 (*) [1..3]
[1,2,6]
Prelude> scanr1 (*) [1..3]
[6,6,3]
So in the first case we have (((1 * 1) * 2) * 3), whereas in the second case it's (1 * (2 * (1 * 3))).
foldr is a really simple function idea: get a function which combines two arguments, get a starting point, a list, and compute the result of calling the function on the list in that way.
Here's a nice little hint about how to imagine what happens during a foldr call:
foldr (+) 0 [1,2,3,4,5]
=> 1 + (2 + (3 + (4 + (5 + 0))))
We all know that [1,2,3,4,5] = 1:2:3:4:5:[]. All you need to do is replace [] with the starting point and : with whatever function we use. Of course, we can also reconstruct a list in the same way:
foldr (:) [] [1,2,3]
=> 1 : (2 : (3 : []))
We can get more of an understanding of what happens within the function if we look at the signature:
foldr :: (a -> b -> b) -> b -> [a] -> b
We see that the function first gets an element from the list, then the accumulator, and returns what the next accumulator will be. With this, we can write our own foldr function:
foldr :: (a -> b -> b) -> b -> [a] -> b
foldr f a [] = a
foldr f a (x:xs) = f x (foldr f a xs)
And there you are; you should have a better idea as to how foldr works, so you can apply that to your problems above.
The fold* functions can be seen as looping over the list passed to it, starting from either the end of the list (foldr), or the start of the list (foldl). For each of the elements it finds, it passes this element and the current value of the accumulator to what you have written as a lambda function. Whatever this function returns is used as the value of the accumulator in the next iteration.
Slightly changing your notation (acc instead of xs) to show a clearer meaning, for the first left fold
a = foldl (\acc y -> 10*acc - y) 0 [1, 2, 3]
= foldl (\acc y -> 10*acc - y) (0*1 - 1) [2, 3]
= foldl (\acc y -> 10*acc - y) -1 [2, 3]
= foldl (\acc y -> 10*acc - y) (10*(-1) - 2) [3]
= foldl (\acc y -> 10*acc - y) (-12) [3]
= foldl (\acc y -> 10*acc - y) (10*(-12) - 3) []
= foldl (\acc y -> 10*acc - y) (-123) []
= (-123)
And for your first right fold (note the accumulator takes a different position in the arguments to the lambda function)
c = foldr (\y acc -> y - 10*acc) 0 [1, 2, 3]
= foldr (\y acc -> y - 10*acc) (3 - 10*0) [1, 2]
= foldr (\y acc -> y - 10*acc) 3 [1, 2]
= foldr (\y acc -> y - 10*acc) (2 - 10*3) [1]
= foldr (\y acc -> y - 10*acc) (-28) [1]
= foldr (\y acc -> y - 10*acc) (1 - 10*(-28)) []
= foldr (\y acc -> y - 10*acc) 281 []
= 281