How to create a recursive zipWith function in Haskell? - list

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

Related

Calling helper function to reverse lists, then zipping lists in Haskell

I'm new to Haskell and I've been trying for hours to get these two functions to work together to produce a zipped reverse list using recursion and without built-in functions.
Here's the helper function to reverse the lists:
reverseList :: [x] -> [x]
reverseList [] = []
reverseList xs = last xs : reverseList (init xs)
Then here's the zipper function
ZipRevLists2 :: [x] -> [y] -> [(x, y)]
ZipRevLists2 _ [] = []
ZipRevLists2 [] _ = []
ZipRevLists2 (x:xs) = reverseList xs
ZipRevLists2 (y:ys) = reverseList ys
ZipRevLists2 (x:xs) (y:ys) = (x,y) : ZipRev2Lists xs ys
I'm trying to learn from learnyouahaskell.com but the only examples are in "ghci>" and not really function form.
Thanks, I finally got it!
The Zip function
zip' :: [x] -> [y] -> [(x,y)]
zip' _ [] = []
zip' [] _ = []
zip' (x:xs) (y:ys) = (x,y):zip' xs ys
and the main function
zipRevLists2 :: [Int] -> [Char] -> [(Int,Char)]
zipRevLists2 _ [] = []
zipRevLists2 [] _ = []
zipRevLists2 (x:xs) (y:ys) = zip' (reverseList (x:xs)) (reverseList (y:ys))

How to implement a function using bind (>>=)

I wrote a filter function:
f :: (a -> Bool) -> [a] -> [a]
f p xs = case xs of
[] -> []
x : xs' -> if p x
then x : f p xs'
else f p xs'
To understand bind, I want to implement this using bind.
What I was thinking about:
f p xs = xs >>= (\x xs -> if p x then x : f p xs else f p xs)
But I get this error:
* Couldn't match expected type `[a]' with actual type `[a] -> [a]'
* The lambda expression `\ x xs -> ...' has two arguments,
but its type `a -> [a]' has only one
In the second argument of `(>>=)', namely
`(\ x xs -> if p x then x : f p xs else f p xs)'
In the expression:
xs >>= (\ x xs -> if p x then x : f p xs else f p xs)
* Relevant bindings include
xs :: [a] (bound at <interactive>:104:5)
p :: a -> Bool (bound at <interactive>:104:3)
f :: (a -> Bool) -> [a] -> [a] (bound at <interactive>:104:1)
Successfully did it using foldr:
f p xs = foldr (\x xs -> if p x then x : f p xs else f p xs) [] xs
What's going wrong?
To understand bind, i want to implement this as bind.
There is no bind here. The bind is added in case of a do expression. The above is not a do-expression, so there is no bind here.
You can however write this with bind, like:
f p xs = xs >>= \x -> if p x then [x] else []
but this is not a literal mapping of the original function, we simply make use of the instance Monad [] implementation here. Nevertheless, your f is just filter :: (a -> Bool) -> [a] -> [a] here.
To understand bind, first implement the no-op:
id_list xs = concat [ [x] | x <- xs ] = [ y | x <- xs, y <- [x ] ]
Now for the filter, augment it as
filter p xs = concat [ [x | p x] | x <- xs ] = [ y | x <- xs, y <- [x | p x] ]
How is this code using bind, you ask? If we're using MonadComprehensions, it does.
The explicit do-notation re-write is straightforward:
id_list xs = do { x <- xs ; y <- [ x ] ; return y }
filter p xs = do { x <- xs ; y <- [ x | p x] ; return y }
And of course, for lists,
[x] == return x
[x | p x] == if p x then return x else mzero
mzero == []
concat == join
This brings us back to an explicitly recursive way to code filter as
filter p [] = []
filter p (x:xs) = [x | p x] ++ filter p xs
With bind, we think in terms of transforming each element of the list individually, into the list of results (none, one, or several) for that one input element. Your foldr-based code breaks this.
So, the code itself is just
filter_bind p xs = xs >>= (\x -> [x | p x])
because we have
xs >>= f == join (fmap f xs)
== concat (map f xs)
== concat [ f x | x <- xs ]
== foldr (++) []
[ f x | x <- xs ]
with the last snippet corresponding to the explicitly recursive definition above.
See also
How does the List monad work in this example?
Haskell Monad - How does Monad on list work?
etc.

zipWith Function Implemented Using Map and Zip Functions

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

Haskell own function to merge two lists

I need to write a function to merge two lists. Exactly like '++' is working.
let x = merge [1,2,3] [3,3,4] -- should output [1,2,3,3,3,4]
How should it be done?
Edit: solution is
merge :: [a] -> [a] -> [a]
merge [] ys = ys
merge (x:xs) ys = x : (merge xs ys)
Maybe something like this.
merge :: (a -> a -> Bool) -> [a] -> [a] -> [a]
merge pred xs [] = xs
merge pred [] ys = ys
merge pred (x:xs) (y:ys) =
case pred x y of
True -> x: merge pred xs (y:ys)
False -> y: merge pred (x:xs) ys
(++) xs ys = merge (\x y -> compare x y == LT) xs ys
Or, if you just need to repeat the functionality of (++), you can look up it's definition with hoogle which eventually leads you to the source code
(++) [] ys = ys
(++) (x:xs) ys = x : xs ++ ys

Implement insert in haskell with foldr

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