Haskell: How to subtract numbers in a list with foldr? - haskell

when you add numbers in a list with foldr it works:
sumIntegers :: [Integer] -> Integer
sumIntegers xs = foldr (+) 0 xs
but to substract doesn't work the same way because
minus minus = plus. [2,3,4,5] is like: 2-3+4-5.
subtractNums' :: Num a => [a] -> a
subtractNums' xs = foldr (-) 0 xs
subtractNums :: Num a => [a] -> a
subtractNums [] = 0
subtractNums (x:xs) = x - subtractNums xs
What has to be changed?
thank you in advance

Addition is associative (and commutative, meaning it doesn't matter if the identity gets added first on the right, or last on the left), so both foldr and foldl compute the same sum:
foldr (+) 0 [1,2,3] == 1 + (2 + (3 + 0)) == 1 + 2 + 3 == 6
foldl (+) 0 [1,2,3] == ((0 + 1) + 2) + 3 == 1 + 2 + 3 == 6
However, subtraction is not associative; (x - y) - z does not, in general, equal x - (y - z), so foldr and foldl compute two different results:
foldl (-) 0 [1,2,3] == ((0 - 1) - 2) - 3
== (-1 - 2) - 3
== -3 - 3
== -6
foldr (-) 0 [1,2,3] == 1 - (2 - (3 - 0))
== 1 - (2 - 3)
== 1 - -1
== 2
Which function you choose depends on which running difference you actually want to compute.

Related

Why the foldr function gives me a negative result when the list contains a zero?

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).

Got Type Int -> Int instead of Integer and don't know why

I wrote this binarytodecimal-converter getting a compiler error I don't know where it's comming from.
binaryToInteger :: [Bool] -> Integer
binaryToInteger (x:xs) = foldr (\x y z -> (fromEnum x) * 2^y + z) 0 [0..length (x:xs)]
Actually the program should give back the decimal result of a binary number.
Example given:
binaryToInteger [True, True, False] == 1(2^2) + 1*(2^1) + 0*(2^0) == 6*
My error message is the following:
Couldn't match expected type Integer' with actual typeInt -> Int'
* Probable cause: `foldr' is applied to too few arguments
In the expression:
foldr (\ x y z -> (fromEnum x) * 2 ^ y + z) 0 [0 .. length (x : xs)]
In an equation for `binaryToInteger':
binaryToInteger (x : xs)
= foldr
(\ x y z -> (fromEnum x) * 2 ^ y + z) 0 [0 .. length (x : xs)]
The algorithm goes like this:
you start with a = 0 ("a" stands for "accumulator")
for True: double a and add 1 to it
for False: just double a
Example: [True, False, True]
a = 0
True => a becomes 1 (because 0 * 2 + 1 = 1)
False => a becomes 2 (because 1 * 2 = 2)
True => a becomes 5 (because 2 * 2 + 1 = 5)
a = 5 is the solution
In Haskell code:
import Data.List (foldl')
binaryToInteger :: [Bool] -> Integer
binaryToInteger xs = foldl' f 0 xs where
f a True = a * 2 + 1
f a False = a * 2
Don't use exponentiation (^), because it is bad for performance. I used a left-fold, because it is better suited for this problem. The function foldl' has the additional advantage that it is strict, and therefore doesn't introduce a space leak.

The missing folds

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.

haskell expression evaluation

I am new to haskell and I would like you to give me your suggestion about the following haskell expression evaluation.
f xs = foldr (\x n->n+1) 0 xs
function
f [1, 4]
Evaluation
(\x n->n+1) 1 (foldr (\x n->n+1) 0 [4])
= (foldr (\x n->n+1) 0 [4]) + 1
= ((\x n->n+1) 4 (foldr (\x n->n+1) 0 [4])) + 1
= (foldr (\x n->n+1) 0 [] + 1) + 1
= (0 + 1) + 1
= 1 + 1
= 2
First of all we need the foldr implementation:
foldr f z [] = z
foldr f z (x:xs) = f x (foldr f z xs)
now let's try to "trace" our computation f [1, 4]:
f [1, 4] -- rewrite list
f (1:(4:[])) -- replace f function where xs = (1:(4:[]))
foldr (\x n-> (+) n 1 ) 0 (1:(4:[]))
-- using foldr f z (x:xs) = f x (foldr f z xs)
-- where f = (\x n -> (+) n 1), z = 0, x = 1, xs = (4:[])
(\x n ->(+) n 1) 1 ( foldr (\x n -> (+) n 1) 0 (4:[]))
-- lambda function will be evaluated with x = 1, n = ( foldr (\x n -> n+1) 0 (4:[]))
(+) (foldr (\x n -> n+1) 0 (4:[])) 1
-- (+) will try to evaluate first parameter
-- foldr will be applied with f = (\x n -> (+) n 1), z = 0, x = 4, xs = []
(+) ((\x n -> (+) n 1) 4 (foldr (\x n -> (+) n 1) 0 [] )) 1
-- now again the lambda will be evaluated where x = 4 and n = (foldr (\x n -> (+) n 1) 0 [] )
(+) ( (+) (foldr (\x n -> (+) n 1) 0 [] ) 1 ) 1
-- now foldr will be evaluated again but this time first form will be used, so just z counts: f = (\x n -> (+) n 1), z = 0, [] = []
(+) ( (+) ( 0 ) 1 ) 1
-- now just go with the flow
(+) ( (+) 0 1 ) 1
(+) ( 1 ) 1
(+) 1 1
2

Haskell - eliminate prime numbers from a list

I want to write a function wp (without primes) which removes all the primes from a list
of numbers. Thus, wp [1, 2, 3, 4, 5, 6, 7] = [1, 4, 6].
I tried coding it like this:
wp :: [Int] -> [Int]
prime :: Int -> Bool
prime n = if f n > 0 then False else True
where f n = foldl (\acc x -> if n `mod` x == 0 then acc = acc + 1 else acc = acc + 0) 0 [2..n-1]
wp xs = filter (not.prime) xs
But when compiling it, I get the "parse error on input =" error but I can't find my syntax error. Any ideas?
Your problem is in the use of acc = acc + x. You just need to write it as acc + 1 or acc + 0 (or just acc really) instead. Also, I would recommend writing the function signature on top of the function definition, rather than a C-style list at the top.
Finally, I should note that wp will not include 1 in the result, so you will have to manually include it.
prime :: Int -> Bool
prime n = if f n > 0 then False else True
where f n = foldl (\acc x -> if n `mod` x == 0 then acc + 1 else acc) 0 [2..n-1]
wp :: [Int] -> [Int]
wp xs = 1 : filter (not.prime) xs

Resources