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
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.
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 am trying to enumerate all the possible merges of two lists.
In example inserting "bb" into "aaa" would look like
["bbaaa", "babaa", "baaba", "baaab", "abbaa", "ababa", "abaab", "aabba", "aabab", "aaabb"]
What I currently did is this
import Data.List
insert'' :: Char -> String -> [(String, String)] -> String
insert'' _ _ ([]) = []
insert'' h b ((x, y):xs) =
(x ++ [h] ++ (insert' (b, y))) ++ (insert'' h b xs)
insert' :: (String, String) -> String
insert' ([], ys) = ys
insert' (xs, ys) =
insert'' h b lists
where
h = head xs
b = tail xs
lists = zip (tails ys) (inits ys)
This returns for ("aaa", "bb")
"bbaaababaaabaababbaababaababbabababb"
a concatenated string, I tried making it a list of strings, but I just cannot wrap my head around this function. I always seems to get infinite type construction.
How could I rewrite the function, so it would return a list of strings?
An other implementation idea as in Daniel Wagners first post is to choose in each step a element from one of the lists and prepending it to the results generated by the function called with only the remaining parts of the list:
interleave :: [a] -> [a] -> [[a]]
interleave xs [] = [xs]
interleave [] ys = [ys]
interleave xs#(x : xs') ys#(y : ys') =
map (x :) (interleave xs' ys) ++ map (y :) (interleave xs ys')
For your intial example this produces:
ghci> interleave "bb" "aaa"
["bbaaa","babaa","baaba","baaab","abbaa","ababa","abaab","aabba","aabab","aaabb"]
Here is one implementation idea: for each element in the first list, we will choose (nondeterministically) a position in the second list to insert it, then recurse. For this to work, we first need a way to nondeterministically choose a position; thus:
choose :: [a] -> [([a], [a])]
choose = go [] where
go before xs = (before, xs) : case xs of
[] -> []
x:xs -> go (x:before) xs
For example:
> choose "abcd"
[("","abcd"),("a","bcd"),("ba","cd"),("cba","d"),("dcba","")]
Now we can use this tool to do the insertion:
insert :: [a] -> [a] -> [[a]]
insert [] ys = [ys]
insert (x:xs) ys = do
(before, after) <- choose ys
rest <- insert xs (reverse after)
return (before ++ [x] ++ rest)
In ghci:
> insert "ab" "cde"
["abcde","aebcd","adebc","acdeb","cabde","caebd","cadeb","dcabe","dcaeb","edcab"]
In this answer, I will give the minimal change needed to fix the code you already have (without completely rewriting your code). The first change needed is to update your type signatures to return lists of strings:
insert'' :: Char -> String -> [(String, String)] -> [String]
insert' :: (String, String) -> [String]
Now your compiler will complain that the first clause of insert' is returning a String instead of a [String], which is easily fixed:
insert' ([], ys) = [ys]
...and that the second clause of insert'' is trying to append a String to a [String] when running [h] ++ insert' (b, y). This one takes some thinking to figure out what you really meant; but my conclusion is that instead of x ++ [h] ++ insert' (b, y), you really want to run \t -> x ++ [h] ++ t for each element in insert' (b, y). Thus:
insert'' h b ((x, y):xs) =
(map (\t -> x ++ [h] ++ t) (insert' (b, y))) ++ (insert'' h b xs)
The complete final code is:
import Data.List
insert'' :: Char -> String -> [(String, String)] -> [String]
insert'' _ _ ([]) = []
insert'' h b ((x, y):xs) =
(map (\t -> x ++ [h] ++ t) (insert' (b, y))) ++ (insert'' h b xs)
insert' :: (String, String) -> [String]
insert' ([], ys) = [ys]
insert' (xs, ys) =
insert'' h b lists
where
h = head xs
b = tail xs
lists = zip (tails ys) (inits ys)
Now ghci will happily produce good answers:
> insert' ("aaa", "bb")
["bbaaa","babaa","baaba","baaab","abbaa","ababa","abaab","aabba","aabab","aaabb"]
So far I have:
miZipWith f [] [] = []
miZipWith f (x:xs) [] = []
miZipWith f [] (y:ys) = []
miZipWith f (x:xs) (y:ys) = f y: miZipWith f xs ys
----miZipWith f (x:xs) (y:ys) = f x : f y : miZipWith f xs ys
But this only "zips" the function f with the second list. How do I include the first list too?
*Main> miZipWith (*2) [1,2,3,4] [5,6,1]
[10,12,2]
The zipWith function goes like this:
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWith f (x:xs) (y:ys) = f x y : zipWith f xs ys
zipWith _ _ _ = []
Your assumption is that the function f takes only one argument, but it in fact takes two (the head of both lists).
How to implement insert using foldr in haskell.
I tried:
insert'' :: Ord a => a -> [a] -> [a]
insert'' e xs = foldr (\x -> \y -> if x<y then x:y else y:x) [e] xs
No dice.
I have to insert element e in list so that it goes before first element that is larger or equal to it.
Example:
insert'' 2.5 [1,2,3] => [1.0,2.0,2.5,3.0]
insert'' 2.5 [3,2,1] => [2.5,3.0,2.0,1.0]
insert'' 2 [1,2,1] => [1,2,2,1]
In last example first 2 is inserted one.
EDIT:
Thanks #Lee.
I have this now:
insert'' :: Ord a => a -> [a] -> [a]
insert'' e xs = insert2 e (reverse xs)
insert2 e = reverse . snd . foldr (\i (done, l) -> if (done == False) && (vj e i) then (True, e:i:l) else (done, i:l)) (False, [])
where vj e i = e<=i
But for this is not working:
insert'' 2 [1,3,2,3,3] => [1,3,2,2,3,3]
insert'' 2 [1,3,3,4] => [1,3,2,3,4]
insert'' 2 [4,3,2,1] => [4,2,3,2,1]
SOLUTION:
insert'' :: Ord a => a -> [a] -> [a]
insert'' x xs = foldr pom poc xs False
where
pom y f je
| je || x > y = y : f je
| otherwise = x : y : f True
poc True = []
poc _ = [x]
Thanks #Pedro Rodrigues (It just nedded to change x>=y to x>y.)
(How to mark this as answered?)
You need paramorphism for that:
para :: (a -> [a] -> r -> r) -> r -> [a] -> r
foldr :: (a -> r -> r) -> r -> [a] -> r
para c n (x : xs) = c x xs (para c n xs)
foldr c n (x : xs) = c x (foldr c n xs)
para _ n [] = n
foldr _ n [] = n
with it,
insert v xs = para (\x xs r -> if v <= x then (v:x:xs) else (x:r)) [v] xs
We can imitate paramorphisms with foldr over init . tails, as can be seen here: Need to partition a list into lists based on breaks in ascending order of elements (Haskell).
Thus the solution is
import Data.List (tails)
insert v xs = foldr g [v] (init $ tails xs)
where
g xs#(x:_) r | v <= x = v : xs
| otherwise = x : r
Another way to encode paramorphisms is by a chain of functions, as seen in the answer by Pedro Rodrigues, to arrange for the left-to-right information flow while passing a second copy of the input list itself as an argument (replicating the effect of tails):
insert v xs = foldr g (\ _ -> [v]) xs xs
where
g x r xs | v > x = x : r (tail xs) -- xs =#= (x:_)
| otherwise = v : xs
-- visual aid to how this works, for a list [a,b,c,d]:
-- g a (g b (g c (g d (\ _ -> [v])))) [a,b,c,d]
Unlike the version in his answer, this does not copy the rest of the list structure after the insertion point (which is possible because of paramorphism's "eating the cake and having it too").
Here's my take at it:
insert :: Ord a => a -> [a] -> [a]
insert x xs = foldr aux initial xs False
where
aux y f done
| done || x > y = y : f done
| otherwise = x : y : f True
initial True = []
initial _ = [x]
However IMHO using foldr is not the best fit for this problem, and for me the following solution is easier to understand:
insert :: Int -> [Int] -> [Int]
insert x [] = [x]
insert x z#(y : ys)
| x <= y = x : z
| otherwise = y : insert x ys
I suppose fold isn't handy here. It always processes all elements of list, but you need to stop then first occurence was found.
Of course it is possible, but you probable don't want to use this:
insert' l a = snd $ foldl (\(done, l') b -> if done then (True, l'++[b]) else if a<b then (False, l'++[b]) else (True, l'++[a,b])) (False, []) l