I am writing a function my_map which takes a unary function and a list and returns the list resulting from mapping the function over all elements of the input list.
Main> my_map (^3) [1..5]
[1,8,27,64,125]
I tried it like this:
my_map :: (a -> b) -> [a] -> [b]
my_map f [] = []
my_map f (x:xs) = foldr (\x xs -> (f x):xs) [] xs
But after running above, I get only [8,27,64,125]
. the first number 1
is not displaying in output.
Can anybody help me?
You are using the (x:xs) pattern in your arguments, but when you apply the fold, you only apply it to the xs part, which means your first element ie the one that x represents never gets processed. You need to change it to this:
my_map :: (a -> b) -> [a] -> [b]
my_map f xs = foldr (\y ys -> (f y):ys) [] xs
Since you are using foldr
, you do not need to explicitly handle the empty list case. Moreoever, you do not need to specify the list in (x:xs) format.
Finally, my own preference is to avoid using the same name for function inputs and any helper functions or expressions in the function definition.That is why, I have used xs
for the input list and y
and ys
for the parameters passed to the lambda.
"shree.pat18" is perfectly right, and also the comments are valuable. I learned a lot from that. Just make it better visible, and to explain the alternatives...
-- The problem is here ....................... vv
my_map f (x:xs) = foldr (\x xs -> (f x):xs) [] xs
-- --
The remaining part xs
is aplied to foldr
.
To fix just this, apply the whole list. This can be done by placing xx@
before (x:xs)
. By that, the whole list is bound to xx
.
-- vvv ........... see here ............... vv
my_map f xx@(x:xs) = foldr (\x xs -> (f x):xs) [] xx
-- --- --
Note: foldr
can already deal with [] as input. Hence, my_map f [] = []
is not needed. But foldr
would not be called when you apply []
to my_map
. To get rid of my_map f [] = []
, you need to remove the pattern matching, because (x:xs)
matches only to lists with at least one element.
main :: IO ()
main = print $ my_map (^(3 :: Int)) ([1..5] :: [Integer])
my_map :: (a -> b) -> [a] -> [b]
my_map f xx = foldr (\x xs -> (f x):xs) [] xx
The answer is complete here. The rest below is for pleasure.
If you want to reduce the lambda expression (\\x xs -> (fx):xs)
, as suggested by "Aadit M Shah"...
(:)
is equal to (\\x xs -> x:xs)
, because :
is an operator and its function is (:)
.
can be used to combine the function f
with (:)
, hence (\\x xs -> (fx):xs)
is equal to ((:) . f)
main :: IO ()
main = print $ my_map (^(3 :: Int)) ([] :: [Integer])
my_map :: (a -> b) -> [a] -> [b]
my_map f xx = foldr ((:) . f) [] xx
A function of the form
-- v v
f a b c = .... c
can be reduced to
-- v v
f a b = ....
and a function of the form
-- v v v v
f a b c = .... b c
can be reduced to
-- v v v v
f a = ....
and so on, by currying.
Hence, my_map f xx = foldr ((:) . f) [] xx
equals my_map f = foldr ((:) . f) []
.
flip
flips the first two parameters.
Example, the following functions are equal:
f' a b c = (\c' b' a' -> ((a' - b') / c')) b a c
f'' a b c = flip (\c' b' a' -> ((a' - b') / c')) a b c
f''' = flip (\c' b' a' -> ((a' - b') / c'))
Hence, the following code works as well.
main :: IO ()
main = print $ my_map (^(3 :: Int)) ([1..5] :: [Integer])
my_map :: (a -> b) -> [a] -> [b]
my_map f = flip foldr [] ((:) . f)
But we can not get rid of f
as above, because of the form in the expression flip foldr [] ((:) . f)
.
If we remove f
...
`((:) . f)` has type `a -> [a] -> [a]
-- v
`((:) . )` has type `(a -> a) -> a -> [a] -> [a]`
and
`flip foldr []` has type `Foldable t => (a1 -> [a2] -> [a2]) -> t a1 -> [a2]`
hence
f :: a -> a
is passed to
((:) . )
becomming
a -> [a] -> [a]
is passed to
flip foldr []
becomming
t a1 -> [a2]
Hence,
main :: IO ()
main = print $ my_map (^(3 :: Int)) ([1..5] :: [Integer])
my_map :: (a -> b) -> [a] -> [b]
my_map = flip foldr [] . ((:) . )
works nicely.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.