A map function that operates on pairs - haskell

I am trying to write a function which is like map, but which takes functions of type (a, a) -> b as its first argument. However, I get the error
<interactive>:474:11: error:
Parse error in pattern: \ (x, y) -> f x y
with the following code:
Prelude> :{
Prelude| mappairs :: ((a, a) -> b) -> [a] -> [b]
Prelude| mappairs (\(x,y) -> f x y) xs = foldr (\(x, y) acc -> (f x y : acc)) [] xs
Prelude| :}
What is the problem?

The pattern:
\(x,y) -> f x y
in the clause:
mappairs (\(x,y) -> f x y) xs = foldr (\(x, y) acc -> (f x y : acc)) [] xs
is indeed not valid, since (->) is not a data constructor.
You can however use zipWith :: (a -> b -> c) -> [a] -> [b] -> [c] here:
mappairs :: ((a, a) -> b) -> [a] -> [b]
mappairs _ [] = []
mappairs f xa#(_:xs) = zipWith (curry f) xa xs
For example:
> mappairs (\(x,y) -> x+y) [1,4,2,5]
[5,6,7]
But it looks more "Haskell-ish" to omit the tuples, and thus use a function directly:
mappairs :: (a -> a -> b) -> [a] -> [b]
mappairs _ [] = []
mappairs f xa#(_:xs) = zipWith f xa xs

Related

Applying f to each element and return the result as list

I want that my function someZip returns the resulting list from applying f to each element.
This is what I got so far:
someZip :: (a -> b -> c -> d) -> [(a,b,c)] -> [d]
someZip f (x:xs) (y:ys) (z:zs) = f x y z : someZip f xs ys zs
I've tried different approaches, but I can't find a solution to this problem.
I am completly lost right now, what am I missing here?
The function you've written and the type signature you've targeted are incongruous. If you like the type signature, you need to alter the definition
someZip :: (a -> b -> c -> d) -> [(a,b,c)] -> [d]
someZip _ [] = []
someZip f ((x,y,z):ts) = f x y z : someZip f ts
This, incidentally, can be written in terms of fmap.
someZip :: (a -> b -> c -> d) -> [(a,b,c)] -> [d]
someZip f = fmap (\(x, y, z) -> f x y z)
If you prefer to keep the implementation and change the type signature, you'll need to take more arguments
someZip :: (a -> b -> c -> d) -> [a] -> [b] -> [c] -> [d]
someZip f (x:xs) (y:ys) (z:zs) = f x y z : someZip f xs ys zs
someZip _ _ _ _ = []
Incidentally, this function is actually zipWith3
someZip :: (a -> b -> c -> d) -> [a] -> [b] -> [c] -> [d]
someZip = zipWith3

Haskell foldr unexpectedly gives an error

Why does writing map using foldr this way
map' :: (a -> b) -> [a] -> [b]
map' f xs = foldr (\x acc -> f x : acc) []
give the following error?
test.hs:2:13: error:
• Couldn't match expected type ‘[b]’ with actual type ‘t0 a -> [b]’
• Probable cause: ‘foldr’ is applied to too few arguments
In the expression: foldr (\ x acc -> f x : acc) []
In an equation for ‘map'’:
map' f xs = foldr (\ x acc -> f x : acc) []
• Relevant bindings include
xs :: [a] (bound at test.hs:2:8)
f :: a -> b (bound at test.hs:2:6)
map' :: (a -> b) -> [a] -> [b] (bound at test.hs:2:1)
|
2 | map' f xs = foldr (\x acc -> f x : acc) []
| ^^^^^^^^^^^^^^^^^^^^^^^^^
You don't use xs. You can either write:
map' f xs = foldr (\x acc -> f x : acc) [] xs
or
map' f = foldr (\x acc -> f x : acc) []

Why does zipWith.zipWith work?

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

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

Resources