mapFunctor :: Functor f => (a -> b) -> [f a] -> [f b]
which this function supposed to be a generalization of map. It works the same as map function, and works for any Functors, not just Maybe.
I am stuck on it. Any hints will be helpful! Thanks.
Play the types jigsaw puzzle / connect the wires (whichever metaphor you prefer):
mapFunctor :: Functor f
=> (a -> b) -> [f a] -> [f b]
mapFunctor f [] = []
mapFunctor f (x:xs) = (y:ys)
where
-- (x:xs) :: [f a]
-- xs :: [f a]
-- x :: f a
-- f :: a -> b
-- fmap f :: f a -> f b
-- fmap f x :: f b
-- (y:ys) :: [f b]
-- y :: f b
-- ys :: [f b]
-- mapFunctor f :: [f a] -> [f b]
-- mapFunctor f xs :: [f b]
y = ....
ys = .....
When you learn more you'll see that the [] type is also a Functor, so your function is just fmap . fmap. But that'll come later.
This is just a combination of map and fmap. The fmap :: Functor f => (a -> b) -> f a -> f b is a function that performs a mapping for each type that is an instance of the Functor typeclass and map :: (c -> d) -> [c] -> [d] is used to create a function that contains the result of applying a function to each item.
I leave it as an exercise to combine the two to a function mapFunctor:
mapFunctor :: Functor f => (a -> b) -> [f a] -> [f b]
mapFunctor = …
Related
There is some case where I don't understand how foldr and foldl are used in function.
Here is a couple of example, I then explain why I don't understand them:
-- Two implementation of filter and map
map' f = foldr (\x acc -> (f x):acc) []
map'' f xs = foldl (\acc x -> acc ++ [(f x)]) [] xs
filter' f xs = foldr(\x acc -> if(f x) then x:acc else acc) [] xs
filter'' f = foldl(\acc x -> if(f x) then acc++[x] else acc) []
Why does map'' makes the use of xs but non map'? Shouldn't map' need a list for the list comprehension formula as well?
Same case for filter' vs filter''.
Here is an implementation which insert elements in a sorted sequence:
insert e [] = [e]
insert e (x:xs)
| e > x = x: insert e xs
| otherwise = e:x:xs
sortInsertion xs = foldr insert [] xs
sortInsertion'' xs = foldl (flip insert) [] xs
Why are the argument for insert flipped in sortInsertion ([] xs) (empty list and list) compare to the definition of insert(e []) (element and empty list)
Why does map'' makes the use of xs but non map'? Shouldn't map' need a list for the list comprehension formula as well? Same case for filter' vs filter''.
This is called “eta-reduction” and it’s a common way of omitting redundant parameter names (“point-free style”). Essentially whenever you have a function whose body is just an application of a function to its argument, you can reduce away the argument:
add :: Int -> Int -> Int
add x y = x + y
-- “To add x and y, call (+) on x and y.”
add :: (Int) -> (Int) -> (Int)
add x y = ((+) x) y
-- “To add x, call (+) on x.”
add :: (Int) -> (Int -> Int)
add x = (+) x
-- “To add, call (+).”
add :: (Int -> Int -> Int)
add = (+)
More precisely, if you have f x = g x where x does not appear in g, then you can write f = g.
A common mistake is then wondering why f x = g . h x can’t be written as f = g . h. It doesn’t fit the pattern because the (.) operator is the top-level expression in the body of f: it’s actually f x = (.) g (h x). You can write this as f x = (((.) g) . h) x and then reduce it to f = (.) g . h or f = fmap g . h using the Functor instance for ->, but this isn’t considered very readable.
Why are the argument for insert flipped in sortInsertion
The functional parameters of foldr and foldl have different argument order:
foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b
foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b
Or, with more verbose type variable names:
foldr
:: (Foldable container)
=> (element -> accumulator -> accumulator)
-> accumulator -> container element -> accumulator
foldl
:: (Foldable container)
=> (accumulator -> element -> accumulator)
-> accumulator -> container element -> accumulator
This is just a mnemonic for the direction that the fold associates:
foldr f z [a, b, c, d]
==
f a (f b (f c (f d z))) -- accumulator on the right (second argument)
foldl f z [a, b, c, d]
==
f (f (f (f z a) b) c) d -- accumulator on the left (first argument)
That is partial function application.
map' f = foldr (\x acc -> (f x):acc) []
is just the same as
map' f xs = foldr (\x acc -> (f x):acc) [] xs
if you omit xs on both sides.
However, beside this explanation, I think you need a beginner book for Haskell. Consider LYAH.
I am new in Haskell. Can anyone explain the difference and the usage of Ord a?
Now I'm familiar with [a] -> [a] -> [a] things. But this,
Ord a => [a] -> [a] -> [a]
please explain me in detail.
The difference is in the constraint, Ord a => a here a has type a but not any a, an a that is an instance of Ord typeclass, example:
here I will change a little bit the type result only to show you can use the functions of the interface:
canBeOrderedList :: Ord a => [a] -> [a] -> [Bool]
canBeOrderedList xs ys = zipWith (>) xs ys
here you can do whatever generic function you want, a here is not restricted, so it can be Ord or Eq or both or none, can be functions, can be Ints can be anything
anyListTypeConcat :: [a] -> [a] -> [a]
anyListTypeConcat xs ys = xs ++ ys
so:
anyListTypeConcat [True, False] [False, True]
=> [True,False,False,True]
here you concatted the two list, so far so good, here:
canBeOrderedList [1,2,3] [4,1,2]
=> [False,True,True]
you can use (>) with numbers but, what about:
data Some = A | B | C deriving (Eq, Show)
anyListTypeConcat [A, A] [B, C]
=> [A,A,B,C]
but:
canBeOrderedList [A,A,B] [C,A,A]
error:
• No instance for (Ord Some)
arising from a use of ‘canBeOrderedList’
• In the expression: canBeOrderedList [A, A, B] [C, A, A]
In an equation for ‘it’: it = canBeOrderedList [A, A, B] [C, A, A]
You cannot order that list, but you may if you change the data type:
data Some = A | B | C deriving (Eq, Show, Ord)
canBeOrderedList [A,A,B] [C,A,A]
=> [False,False,True]
And that's essentially the difference
Consider:
-- merge :: [a] -> [a] -> [a] ?
merge [] ys = ys
merge xs [] = xs
merge (x:xs) (y:ys)
| y < x = y : merge (x:xs) ys
| otherwise = x : merge xs (y:ys)
In particular, look at the second-to-last line. See that (<) operator?
ghci> :i (<)
class Eq a => Ord a where
...
(<) :: a -> a -> Bool
We can see here that the less-than operator does not exist for type not of class Ord; that merge function therefore makes no sense unless we have Ord a. We therefore rewrite its type signature as:
merge :: Ord a => [a] -> [a] -> [a]
I am attempting to implement the zipWith function via the zip and map functions, but I am getting an error that reads: "error: parse error on input '::' My code is below and and I am unsure of what I have done wrong
zipWith` :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWith` f x y = zip x $ map f y
You have to use ' symbol and not ` ; then, to combine the function you need to use uncurry:
zipWith' :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWith' f xs ys = map (uncurry f) (zip xs ys)
why is that, well the type of zip is:
zip :: [a] -> [b] -> [(a, b)]
but the function f is f :: (a -> b -> c), so, with the help of uncurry,
uncurry :: (a -> b -> c) -> (a, b) -> c
you can map the function f into the [(a, b)], transforming it into [c].
As Damian points out, zipWith` doesn't work with the trailing backtick -- the backtick has a special meaning in Haskell. Rename it to zipWith'.
zipWith' :: (a -> b -> c) -> [a] -> [b] -> [c]
Then of course you have to actually write the solution. With explicit recursion you've got
zipWith' _ _ [] = []
zipWith' _ [] _ = []
zipWith' f (x:xs) (y:ys) = f x y : zipWith' f xs ys
but using map and zip you could apply it like this:
zipWith' f xs ys = map (\(x,y) -> f x y) . zip xs $ ys
or more easily-read:
zipWith' f xs ys = map (\(x,y) -> f x y) zipped
where zipped = zip xs ys
Here is my own implementation of nub (remove duplicates):
nub :: (Eq a) => [a] -> [a]
nub lista = nub_rec lista []
where
nub_rec :: (Eq a) => [a] -> [a] -> [a]
nub_rec [] acc = acc
nub_rec (x:xs) acc = nub_rec (filter (\y -> if y == x then False else True) xs) (x:acc)
I consider how to use foldr/foldl to implement nub, could you help me ? I can't see a way.
First, your implementation of nub is bit more complex than it needs to be (and it reverses the order of elements in the list). Here's a simpler one:
myNub :: Eq a => [a] -> [a]
myNub (x:xs) = x : filter (/= x) (myNub xs)
myNub [] = []
Now, if we want to use foldr to write a function that will output, not just an "aggregate" but a full list, it's useful to first have a look at the simplest foldr-based function that takes in a list and spits out a list:
myNoop :: [a] -> [a]
myNoop l = foldr (\ x xs -> x : xs) [] l
Given that, the filter must be inserted somewhere. Since I assume this is a homework, I'll leave that to the OP as an exercise :)
Solution only with filter and foldr without direct (or self) recursion:
removeDuplicates :: Eq a => [a] -> [a]
removeDuplicates = foldr (\z ys -> z : filter (/= z) ys) []
I'm trying to write a function named split that takes a list and returns a list of pairs of all the different possiblities to partition it, e.g.
split [4,3,6] = [([],[4,3,6]),([4],[3,6]),([4,3],[6]),([4,3,6],[])]
Now I wrote this
split :: [a] -> [([a],[a])]
split [] = [([],[])]
split (x:xs) = ([],(x:xs)):(zip (map (x:) (map fst split(xs))) (map snd split(xs)))
piece of code and Hugs and the interpreter of my choice gets me this
ERROR file:.\split.hs:3 - Type error in application
*** Expression : map snd split xs
*** Term : map
*** Type : (e -> f) -> [e] -> [f]
*** Does not match : a -> b -> c -> d
error message. What the heck am I doing wrong? Why would (map snd split xs) be of type
(a-> b -> c -> d)?
You've misplaced your parens. Try
split (x:xs) = ([],(x:xs)):(zip (map (x:) (map fst (split xs))) (map snd (split xs)))
Haskell doesn't use parenthesis for function calls in the same way as something like C and Java. When you write map fst split(xs) this is the same as map fst split xs, i.e. the compiler thinks that you are trying to call map with three parameters. Therefore you need to parenthise the call to split like this: map fst (split xs).
What you are effectively trying to write is a simple zipper for a list. The easiest way to implement it is
import Data.List (inits, tails)
split xs = zip (inits xs) (tails xs)
Here's an alternative definition:
splits :: [a] -> [(a, a)]
splits xs = map (flip splitAt xs) [0 .. length xs]
Admittedly, it's not very efficient, but at least it's concise :-)
Another version that's even shorter, and probably more efficient, using inits and tails from Data.List:
splits :: [a] -> [(a, a)]
splits xs = zip (inits xs) (tails xs)
Now let's have a little fun. We can write inits and tails as foldrs, where we use initsA and tailsA to represent what are known as the algebras of the folds:
inits :: [a] -> [[a]]
inits = foldr initsA [[]]
initsA :: a -> [[a]] -> [[a]]
initsA x xss = [] : map (x:) xss
tails :: [a] -> [[a]]
tails = foldr tailsA [[]]
tailsA :: a -> [[a]] -> [[a]]
tailsA x xss = (x : head xss) : xss
Using these algebras, we can further combine them:
splits :: [a] -> [([a], [a])]
splits = foldr splitsA [([], [])]
splitsA :: a -> [([a], [a])] -> [([a], [a])]
splitsA xy xyss = zip (initsA xy xss) (tailsA xy yss)
where (xss, yss) = unzip xyss
So now we have splits defined as a single foldr!