I have a lambda function ((:) . ((:) x)) that I am passing to foldr like so: foldr ((:) . ((:) x)) [] xs where xs is a 2d list. I would like to refactor to make it clearer (so I can better understand it). I imagine it would be done like so:
foldr (\ element acc -> (element:acc) . (x:acc)) [] xs
But this gives me the error:
ex.hs:20:84: error:
• Couldn't match expected type ‘a0 -> b0’ with actual type ‘[[a]]’
• Possible cause: ‘(:)’ is applied to too many arguments
In the second argument of ‘(.)’, namely ‘(x : acc)’
In the expression: (element : acc) . (x : acc)
In the first argument of ‘foldr’, namely
‘(\ element acc -> (element : acc) . (x : acc))’
• Relevant bindings include
acc :: [[a]] (bound at ex.hs:20:60)
element :: [a] (bound at ex.hs:20:52)
xs :: [[a]] (bound at ex.hs:20:30)
x :: [a] (bound at ex.hs:20:28)
prefixes :: [a] -> [[a]] (bound at ex.hs:20:1)
|
20 | prefixes = foldr (\x xs -> [x] : (foldr (\ element acc -> (element:acc) . (x:acc)) [] xs)) []
|
Edit: My all relevant code surrounding this snippet is
prefixes :: Num a => [a] -> [[a]]
prefixes = foldr (\x acc -> [x] : (foldr ((:) . ((:) x)) [] acc)) []
and its invocation is:
prefixes [1, 2, 3]
How can I refactor the lambda ((:) . ((:) x)) to include both its arguments?
You can step-by-step convert it to a lambda.
(:) . ((:) x)
\y -> ((:) . (((:) x)) y -- conversion to lambda
\y -> (:) (((:) x) y) -- definition of (.)
\y -> (:) (x : y) -- rewrite second (:) using infix notation
\y z -> (:) (x : y) z -- add another parameter
\y z -> (x : y) : z -- rewrite first (:) using infix notation
Related
This question already has answers here:
Use foldr to define map in Haskell,
(3 answers)
Closed 3 months ago.
I'm new to Haskell and I want to understand what this syntax means.
This is the context of the function:
map' :: (a -> b) -> [a] -> [b]
map' f xs = foldr (\y ys -> (f y):ys) [] xs
It's defining the map function from the prelude in terms of foldr. I'm confused by what foldr (\y ys -> (f y):ys) [] xs means. Especially the (\y ys -> (f y): ys) part.
In my understanding, y is the first value in the list ys which is the input and the function f is being applied to the y value in the list ys. I understand these values are taken in the context of pattern matching. Kindly correct me if I'm wrong.
Take a look at a simplified definition of foldr (adapted from https://wiki.haskell.org/Foldr_Foldl_Foldl'):
foldr _ z [] = z
foldr f z (x:xs) = f x (foldr f z xs)
The second argument passed to f (ys, in your case) is basically the result of folding the rest of the list, without having to explicitly make the recursive call.
We can compare an explicitly recursive definition of map':
map' f [] = []
map' f (x:xs) = f x : map' xs
to the expansion of your definition of map' using equational reasoning.
map' f (x:xs)
-- by definition of map'
== foldr (\y ys -> f y : ys) [] (x:xs)
-- by definition of foldr
== (\y ys -> f y : ys) x (foldr (\y ys -> f y : ys) [] xs)
-- application of folding function to x...
== (\ys -> f x : ys) (foldr (\y ys -> f y : ys) [] xs)
-- ... and then the recursive fold
== f x : foldr (\y ys -> f y : ys) [] xs
-- by definition of map'
== f x : map' f xs
I'm trying to see the difference in these 2 functions:
dupli = foldl (\acc x -> acc ++ [x,x]) []
dupli = foldr (\ x xs -> x : x : xs) []
I know the difference between foldl and foldr but for the examples I've seen on how it works, using (+), it looks the same except for the method of summing.
Why
dupli = foldr (\acc x -> acc ++ [x,x]) []
gives
/workspaces/hask_exercises/exercises/src/Lib.hs:142:27: error:
* Occurs check: cannot construct the infinite type: a ~ [a]
Expected type: [a]
Actual type: [[a]]
* In the expression: acc ++ [x, x]
In the first argument of `foldr', namely
`(\ acc x -> acc ++ [x, x])'
In the expression: foldr (\ acc x -> acc ++ [x, x]) []
* Relevant bindings include
x :: [a] (bound at src/Lib.hs:142:22)
acc :: [[a]] (bound at src/Lib.hs:142:18)
dupli' :: t [[a]] -> [a] (bound at src/Lib.hs:142:1)
|
142 | dupli' = foldr (\acc x -> acc ++ [x,x]) []
| ^^^^^^^^^^^^
exactly?
Look at the type signatures. (Note: I'm specializing both of these to [] rather than a general Foldable for simplicity here)
foldl :: (b -> a -> b) -> b -> [a] -> b
foldr :: (a -> b -> b) -> b -> [a] -> b
So in foldl, the "accumulator argument" is the first argument to the folding function, whereas in foldr, it's the second.
You mention (+). (+) is a function where the left-hand and right-hand arguments have the same type, so you wouldn't notice the difference. Specifically,
(+) :: Num a => a -> a -> a
But (:) is different.
(:) :: a -> [a] -> [a]
Since your initial accumulator is, in both cases, [], you can use (:) in the foldr case since the accumulator type [a] is the second argument, but in the foldl case we're required to do some tricks with ++.
I am new to Haskell so I don't quite understand most of its errors. I have encountered an error trying to make a higher order function that uses foldl() to read a list and then multiply it by 2 (it automatically reverses it) and I use another another foldl() just to read it, in so reversing it to its original order.
I would be thankful for any help I receive.
here's the error
• Couldn't match expected type ‘[Int]’
with actual type ‘t0 Integer -> [Integer]’
• Probable cause: ‘foldl’ is applied to too few arguments
In the first argument of ‘reverses’, namely
‘(foldl (\ acc x -> (2 * x) : acc) [])’
In the expression: reverses (foldl (\ acc x -> (2 * x) : acc) [])
In an equation for ‘multthr’:
multthr = reverses (foldl (\ acc x -> (2 * x) : acc) [])
|
16 | multthr = reverses(foldl(\acc x-> (2*x):acc)[])
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
here's the source code
reverses::[Int] ->[Int]
reverses = foldl(\acc x-> x:acc)[]
multthr::[Int]->([Int]->[Int])
multthr = reverses(foldl(\acc x-> (2*x):acc)[])
You need to compose your two foldl's with (.), instead of applying one to the other:
reverses :: [a] -> [a]
reverses = foldl (\acc x-> x:acc) []
---- multthr :: [Int] -> ([Int] -> [Int]) -- why??
multthr :: [Int] -> [Int]
---- multthr = reverses (foldl(\acc x-> (2*x):acc)[]) -- causes error
multthr = reverses . foldl (\acc x-> (2*x):acc) []
so that we have
> multthr [1..5]
[2,4,6,8,10]
it :: [Int]
(.) is the functional composition, defined as (f . g) x = f (g x).
Instead of doing the two foldl's you can do one foldr,
mult2 = foldr (\x r -> (2*x) : r) []
but then this is nothing else but, simply, map (2*).
What does the x: mean in this Code
Implementation of inits using foldr
inits :: [a] -> [[a]]
inits = foldr ( \ x y -> [] : (map (x:) y) ) [[]]
This is an effect of the infix operator sectioning [Haskell-wiki]:
(2^) (left section) is equivalent to (^) 2, or more verbosely \x -> 2 ^ x
So (x:) is short for (:) x, or \y -> x : y. The "cons" (:) :: a -> [a] -> [a] is a function that takes an element (type a) and a list (type [a]) and constructs a list with the element followed by the elements in the list.
(x:) :: [a] -> [a] is thus a function that takes a list and prepends that list with x.
We can make the fold function "point free" with:
foldr (((:) [] .) . map . (:)) [[]]
It's a function of a single argument that conses x to some list:
(x:) [] => [x]
(x:) [1, 2] => [x, 1, 2]
Here "conses" means "prepends a value to some list". cons is the "canonical" name of a function that does this. So, the : function is the cons function.
Why does writing map using foldr this way
map' :: (a -> b) -> [a] -> [b]
map' f xs = foldr (\x acc -> f x : acc) []
give the following error?
test.hs:2:13: error:
• Couldn't match expected type ‘[b]’ with actual type ‘t0 a -> [b]’
• Probable cause: ‘foldr’ is applied to too few arguments
In the expression: foldr (\ x acc -> f x : acc) []
In an equation for ‘map'’:
map' f xs = foldr (\ x acc -> f x : acc) []
• Relevant bindings include
xs :: [a] (bound at test.hs:2:8)
f :: a -> b (bound at test.hs:2:6)
map' :: (a -> b) -> [a] -> [b] (bound at test.hs:2:1)
|
2 | map' f xs = foldr (\x acc -> f x : acc) []
| ^^^^^^^^^^^^^^^^^^^^^^^^^
You don't use xs. You can either write:
map' f xs = foldr (\x acc -> f x : acc) [] xs
or
map' f = foldr (\x acc -> f x : acc) []