Reputation: 3
I am learning haskell and I need to define zipWith
function using foldr
.
I can do it using pattern matching and recursion, but that doesn't work for me at the moment. For example:
zipWith' :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWith' f = go
where
go [] _ = []
go _ [] = []
go (x:xs) (y:ys) = f x y : go xs ys
I also understand how folds work, but I can't really think of how I can use them to define zipWith
.
From already thank you very much.
Upvotes: 0
Views: 646
Reputation: 10091
If you only want to do a foldr
on one of the lists, then this isn't too difficult and one of the other answers will help you.
However, if you want to use foldr
on both, this is actually quite a difficult question, and one that was thought to not be possible for quite a while!
We can do it with the following bizarre type:
data Hyp a b = Hyp { invoke :: Hyp b a -> b }
This is the type of hyperfunctions from a
to b
. Here's how it can be used to zip:
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWith c xs ys = invoke (foldr xf xb xs) (foldr yf yb ys)
where
xf x xk = Hyp (\yk -> invoke yk xk x)
xb = Hyp (\_ -> [])
yf y yk = Hyp (\xk x -> c x y : invoke xk yk)
yb = Hyp (\_ _ -> [])
If you want to read more about the problem look here.
Upvotes: 1
Reputation: 875
You can define zipWith'
using foldr
like so:
zipWith' :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWith' f xs ys = fst $ foldr go ([], reverse xs) ys where
go _ (res, []) = (res, [])
go y (res, z:zs) = (f z y : res, zs)
Upvotes: 0
Reputation: 116139
To use foldr
, you need to rewrite your definition in an equivalent way so that it has this form:
zipWith' :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWith' f = go
where
go [] = someConstant
go (x:xs) = someFunction x (go xs)
Indeed, that is equivalent to zipWith' f = foldr someFunction someConstant
.
We need the second list argument, so let's add it as a lambda. The "constant" we met above is actually a function of the second list, since that's the only way to obtain the wanted type:
go [] = \ _list -> [] -- first case complete
go (x:xs) = \ list ->
somehowUse x (go xs) list
Now we can pattern match on list
go [] = \ _list -> [] -- first case complete
go (x:xs) = \ list -> case list of
[] -> ...
(y:ys) -> ...
and now we can follow the original code.
Can you see how to proceed now?
Upvotes: 2