Why does zipWith.zipWith work? - haskell

I am implementing a function combine :: [[a]] -> [[b]] -> (a -> b -> c) -> [[c]] which given two 2D lists, applies a given function f :: a -> b -> c to the entries of the 2D list. In other words:
[[a, b, c], [[r, s, t], [[f a r, f b s, f c t],
combine [d, e, g], [u, v, w], f = [f d u, f e v, f g w],
[h, i, j]] [x, y, z]] [f h x, f i y, f j z]]
Now I suspect that combine = zipWith . zipWith, because I have tried it out and it is giving me the intended results, e.g.
(zipWith . zipWith) (\x y -> x+y) [[1,2,3],[4,5,6]] [[7,8,9],[10,11,12]]
gives the expected result [[8,10,12],[14,16,18]], but I cannot understand why this works, because I don't understand how the type of zipWith . zipWith turns out to be (a -> b -> c) -> [[a]] -> [[b]] -> [[c]].
Is (.) here still carrying out the usual function composition? If so, can you explain how this applies to zipWith?

To infer the type of an expression such as zipWith . zipWith, you can simulate the unification in your head the following way.
The first zipWith has type (a -> b -> c) -> ([a] -> [b] -> [c]), the second (s -> t -> u) -> ([s] -> [t] -> [u]) and (.) has type (m -> n) -> (o -> m) -> (o -> n).
For it to typecheck, you need:
m = (a -> b -> c)
n = ([a] -> [b] -> [c])
o = (s -> t -> u)
m = ([s] -> [t] -> [u]) => a = [s], b = [t], c = [u] because of the first constraint
Then the returned type is o -> n which is (s -> t -> u) -> ([a] -> [b] -> [c]) from the constraints and going one step further (s -> t -> u) -> ([[s]] -> [[t]] -> [[u]]).

Another way of seeing it is that lists with the zipping operation form an Applicative, and the composition (nesting) of Applicatives is still Applicative:
λ import Control.Applicative
λ import Data.Functor.Compose
λ let l1 = ZipList [ZipList [1,2,3], ZipList [4,5,6]]
λ let l2 = ZipList [ZipList [7,8,9], ZipList [10,11,12]]
λ getCompose $ (+) <$> Compose l1 <*> Compose l2
ZipList {getZipList = [ZipList {getZipList = [8,10,12]},
ZipList {getZipList = [14,16,18]}]}
The ZipList newtype is required because "bare" lists have a different Applicative instance, which forms all combinations instead of zipping.

Yes, . is the normal function composition operator:
Prelude> :type (.)
(.) :: (b -> c) -> (a -> b) -> a -> c
One way to look at it is that it takes an a value, first calls the a -> b function, and then uses the return value of that function to call the b -> c function. The result is a c value.
Another way to look at (zipWith . zipWith), then, is to perform an eta expansion:
Prelude> :type (zipWith . zipWith)
(zipWith . zipWith) :: (a -> b -> c) -> [[a]] -> [[b]] -> [[c]]
Prelude> :t (\x -> zipWith $ zipWith x)
(\x -> zipWith $ zipWith x)
:: (a -> b -> c) -> [[a]] -> [[b]] -> [[c]]
Prelude> :t (\x -> zipWith (zipWith x))
(\x -> zipWith (zipWith x))
:: (a -> b -> c) -> [[a]] -> [[b]] -> [[c]]
The type of zipWith itself:
Prelude> :type zipWith
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
So, in the above lambda expression, x must be (a -> b -> c), and hence zipWith x must have the type [a] -> [b] -> [c].
The outer zipWith also needs a function (a1 -> b1 -> c1), which matches zipWith x if a1 is [a], b1 is [b], and c1 is [c].
So, by replacement, zipWith (zipWith x) must have the type [[a]] -> [[b]] -> [[c]], and therefore the type of the lambda expression is (a -> b -> c) -> [[a]] -> [[b]] -> [[c]].

Related

Compose functions into another function

Is there a function for Haskell in the standard library which takes three functions and returns a function which applies the return values of the first two functions to the third function, something like this:
compact :: (a -> b) -> (a -> c) -> (b -> c -> d) -> a -> d
compact a b c = \x -> c (a x) (b x)
Or this:
import Control.Arrow
compact' :: (a -> b) -> (a -> c) -> (b -> c -> d) -> a -> d
compact' a b c = uncurry c . (a &&& b)
So that:
compact (take 1) (drop 2) (++) [1,2,3,4] == [1,3,4]
compact (+10) (*2) (<) 11 == True
compact (+10) (*2) (<) 9 == False
If you reorder the signature to:
(b -> c -> d) -> (a -> b) -> (a -> c) -> a -> d
this is equivalent to liftM2, since ((->) r) is an instance of Monad type class
liftM2 :: Monad m => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r
and
\> liftM2 (++) (take 1) (drop 2) [1, 2, 3, 4]
[1,3,4]
similarly, liftA2 from Control.Applicative:
liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c
\> liftA2 (++) (take 1) (drop 2) [1, 2, 3, 4]
[1,3,4]
liftM2 from Control.Monad is almost the same as your compact function, just with the arguments in a different order.
liftM2 :: Monad m => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r
which in context is the same as:
liftM2 :: (b -> c -> d) -> (a -> b) -> (a -> c) -> a -> d
So:
liftM2 (++) (take 1) (drop 2) [1,2,3,4] == [1,3,4]
liftM2 (<) (+10) (*2) 11 == True
liftM2 (<) (+10) (*2) 9 == False

Haskell: Defining map function using unfold

I have the following Haskell method
unfold :: (a -> Bool) -> (a -> b) -> (a -> a) -> a -> [b]
unfold p h t x
| p x = []
| otherwise = (h x):(unfold p h t (t x))
How can i define the regular prelude map f x method using this given unfold method.
If you define:
map' :: (a -> b) -> [a] -> [b]
map' f = unfold null (f.head) tail
then
\> map' show [1..5]
["1","2","3","4","5"]
\> map' (+1) []
[]

"generalised" scanl

I am trying to write a sort of scanl like function of type:
general_scanl' :: (a->b->a)->(a->b->[c])->a->[b]->[c]
The function is intended to output the same as the following two monstrosities:
general_scanl' f g x y = snd $ foldl' (\(p,q) r -> (f p r,q ++ g p r)) (x,[]) y
or,
general_scanl' f g x y = concat $ zipWith g (scanl f x y) y
The disadvantage of the first definition is that it contains a handwritten lambda.
The disadvantage of the second definition is that it accumulates a list of lists (scanl f x y) which isn't necessary...
My question: is there a cleaner way to define this function?
Many thanks,
You have
Prelude> let general_scanl2 f g z xs = concat $ zipWith g (scanl f z xs) xs
-- :: [a]
Prelude> :t general_scanl2
general_scanl2 :: (a -> b -> a) -- f
-> (a -> b -> [c]) -- g
-> a -- z
-> [b] -- xs
-> [c]
Prelude Data.List> :t mapAccumL
mapAccumL :: (a -> b -> (a, y)) -> a -> [b] -> (a, [y])
So, another way to write this seems to be
import Data.List
g_scanl3 :: (a -> b -> a) -> (a -> b -> [c]) -> a -> [b] -> [c]
g_scanl3 f g z xs = concat . snd $
mapAccumL (\a b-> (f a b, g a b)) z xs

Define map using foldl instead of foldr and an expr

I did it like this – but it is not working:
ma f [] = []
ma f (xs) = foldl (\y ys -> ys++(f y)) [] xs
foldl :: (a -> b -> a) -> a -> [b] -> a
foldr :: (a -> b -> b) -> b -> [a] -> b
Why is there a difference in the function that fold takes. I mean, (a -> b -> a) and (a -> b -> b)?
Is it possible to define map using foldl?
I have another question
I have an expr.
map (:)
I want to know what it will do. I tried to test it but i only get error.
type is map (:) :: [a] -> [[a] -> [a]]
I tried to send in a list of [1,2,3]
Not if you want it to work for infinite as well as finite lists. head $ map id (cycle [1]) must return 1.
foldling over an infinite list diverges (never stops), because foldl is recursive. For example,
foldl g z [a,b,c] = g (g (g z a) b) c
Before g gets a chance to ignore its argument, foldl must reach the last element of the input list, to construct the first call to g. There is no last element in an infinite list.
As for your new question, here's a GHCi transcript that shows that map (:) is a function, and map (:) [1,2,3] is a list of functions, and GHCi just doesn't know how to Show functions:
Prelude> map (:)
<interactive>:1:0:
No instance for (Show ([a] -> [[a] -> [a]]))
Prelude> :t map (:)
map (:) :: [a] -> [[a] -> [a]]
Prelude> map (:) [1,2,3]
<interactive>:1:0:
No instance for (Show ([a] -> [a]))
Prelude> :t map (:) [1,2,3]
map (:) [1,2,3] :: (Num a) => [[a] -> [a]]
Prelude> map ($ [4]) $ map (:) [1,2,3]
[[1,4],[2,4],[3,4]]
Prelude> foldr ($) [4] $ map (:) [1,2,3]
[1,2,3,4]
It becomes more obvious when you swap the type-variable names in one of the functions:
foldl :: (b -> a -> b) -> b -> [a] -> b
foldr :: (a -> b -> b) -> b -> [a] -> b
...because after all, what we need is the result, i.e. [a] -> b. Or, more specially, [a] -> [b], so we might as well substitute that
foldl :: ([b] -> a -> [b]) -> [b] -> [a] -> [b]
foldr :: (a -> [b] -> [b]) -> [b] -> [a] -> [b]
which leaves only one non-list item in each signature, namely the a. That's what we can apply f to, so, in the case of foldl it has to be the 2nd argument of the lambda:
foldl (\ys y -> ys ++ f y)
As Xeo remarks, this isn't done yet, because f y has type b, not [b]. I think you can figure out how to fix that yourself...
ma f [] = []
ma f (xs) = foldl (\ys y -> ys++[(f y)]) [] xs
Works but why does order of arg to lambda matter.
ma f (xs) = foldl (\y ys -> ys++[(f y)]) [] xs gives error

How does the expression `ap zip tail` work

I wondered how to write f x = zip x (tail x) in point free. So I used the pointfree program and the result was f = ap zip tail. ap being a function from Control.Monad
I do not understand how the point free definition works. I hope I can figure it out if I can comprehend it from the perspective of types.
import Control.Monad (ap)
let f = ap zip tail
let g = ap zip
:info ap zip tail f g
ap :: Monad m => m (a -> b) -> m a -> m b
-- Defined in `Control.Monad'
zip :: [a] -> [b] -> [(a, b)] -- Defined in `GHC.List'
tail :: [a] -> [a] -- Defined in `GHC.List'
f :: [b] -> [(b, b)] -- Defined at <interactive>:3:5
g :: ([a] -> [b]) -> [a] -> [(a, b)]
-- Defined at <interactive>:4:5
By looking at the expression ap zip tail I would think that zip is the first parameter of ap and tail is the second parameter of ap.
Monad m => m (a -> b) -> m a -> m b
\--------/ \---/
zip tail
But this is not possible, because the types of zip and tail are completely different than what the function ap requires. Even with taking into consideration that the list is a monad of sorts.
So the type signature of ap is Monad m => m (a -> b) -> m a -> m b. You've given it zip and tail as arguments, so let's look at their type signatures.
Starting with tail :: [a] -> [a] ~ (->) [a] [a] (here ~ is the equality operator for types), if we compare this type against the type of the second argument for ap,
(->) [x] [x] ~ m a
((->) [x]) [x] ~ m a
we get a ~ [x] and m ~ ((->) [x]) ~ ((->) a). Already we can see that the monad we're in is (->) [x], not []. If we substitute what we can into the type signature of ap we get:
(((->) [x]) ([x] -> b)) -> (((->) [x]) [x]) -> (((->) [x]) b)
Since this is not very readable, it can more normally be written as
([x] -> ([x] -> b)) -> ([x] -> [x]) -> ([x] -> b)
~ ([x] -> [x] -> b ) -> ([x] -> [x]) -> ([x] -> b)
The type of zip is [x] -> [y] -> [(x, y)]. We can already see that this lines up with the first argument to ap where
[x] ~ [x]
[y] ~ [x]
[(x, y)] ~ b
Here I've listed the types vertically so that you can easily see which types line up. So obviously x ~ x, y ~ x, and [(x, y)] ~ [(x, x)] ~ b, so we can finish substituting b ~ [(x, x)] into ap's type signature and get
([x] -> [x] -> [(x, x)]) -> ([x] -> [x]) -> ([x] -> [(x, x)])
-- zip tail ( ap zip tail )
-- ap zip tail u = zip u (tail u)
I hope that clears things up for you.
EDIT: As danvari pointed out in the comments, the monad (->) a is sometimes called the reader monad.
There are two aspects to understanding this:
The type magic
The information flow of the implementation
Firstly, this helped me understand the type magic:
1) zip : [a] → ( [a] → [(a,a)] )
2) tail : [a] → [a]
3) zip <*> tail : [a] → [(a,a)]
4) <*> : Applicative f ⇒ f (p → q) → f p → f q
In this case, for <*>,
5) f x = y → x
Note that in 5, f is a type constructor. Applying f to x produces a type. Also, here = is overloaded to mean equivalence of types.
y is currently a place-holder, in this case, it is [a], which means
6) f x = [a] -> x
Using 6, we can rewrite 1,2 and 3 as follows:
7) zip : f ([a] → [(a,a)])
8) tail : f [a]
9) zip <*> tail : f ([a] → [(a,a)]) → f [a] → f [(a,a)]
So, looking at 4, we are substituting as follows:
10) p = [a]
11) q = [(a,a)]
12) f x = [a] → x
(Repetition of 6 here again as 12 )
Secondly, the information flow, i.e. the actual functionality. This is easier, it is clear from the definition of <*> for the Applicative instance of y →, which is rewritten here with different identifier names and using infix style:
13) g <*> h $ xs = g xs (h xs)
Substituting as follows:
14) g = zip
15) h = tail
Gives:
zip <*> tail $ xs (Using 14 and 15)
==
zip xs (tail xs) (Using 13 )

Resources