Applying f to each element and return the result as list - haskell

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

Related

Trying to implement elem with a foldl any

I am new in haskell, i am trying right now to implement "elem" with a "foldl any" in Haskell, but it won't work.
My any :
any' p = foldl' (\y x -> p x || y) False
and this is my elem :
elem' y = foldl' (\z x -> x==y || z) False
my first try was this :
elemfa p y = not (any' (\x -> not (p x)) y)
but i am getting an error everytime
Your elemfa :: Foldable f => (a -> Bool) -> f a -> Bool makes use of any'''', but that function does not exists. If you rewrite this to:
elemfa :: Foldable f => (a -> Bool) -> f a -> Bool
elemfa p y = not (any' (\x -> not (p x)) y)
You can make it more clean with:
elemfa :: Foldable f => (a -> Bool) -> f a -> Bool
elemfa p = not . any' (not . p)
It will at least produce output. This function will check if all elements satisfy the given predicate.
That being said, it is not ideal to use a foldl here for any, elem and elemfa, since that means it will keep iterating over the list, even if it found an element that satisfies the predicate. If you thus work on an infinite list, it will not return True, even if it found an element:
Prelude Data.List> elem' 1 (1 : repeat 2)
… keeps looking …
Here foldr :: Foldable f => (a -> b -> b) -> b -> f a -> b can be used to stop searching once the element has been found, for example:
any' :: Foldable f => (a -> Bool) -> f a -> Bool
any' p = foldr (\x -> (p x ||)) False
elem' :: (Foldable f, Eq a) => a -> f a -> Bool
elem' x = any' (x==)
all' :: Foldable f => (a -> Bool) -> f a -> Bool
all' p = not . any (not . p)

How to update a structure with recursion schemes?

In recursion schemes, how can I construct something with type definition like (Recursive t, CoRecursive t) -> t -> ? -> t
I try to use recursion-schemes to update nodes. Taking list as an example, I can come up with two methods like:
update :: [a] -> Natural -> a -> [a]
update = para palg where
palg Nil _ _ = []
palg (Cons a (u, _)) 0 b = b : u
palg (Cons a (u, f)) n b = a : f (n-1) b
update' :: [a] -> Natural -> a -> [a]
update' = c2 (apo acoalg) where
c2 f a b c = f (a,b,c)
acoalg ([], _, _) = Nil
acoalg (_:as , 0, b) = Cons b $ Left as
acoalg (a:as , n, b) = Cons a $ Right (as, n-1, b)
However, these two implementations are good. In these two implementations, the constructor of ListF and [] appears in both sides of the equation. And the definition does not appear to be unique. Is there a better way to perform List update with recursion schemes?
Recursion schemes is flexible approach. You can also implement your own variant.
(Reuse cata)
zipo :: (Recursive g, Recursive h) => (Base g (h -> c) -> Base h h -> c) -> g -> h -> c
zipo alg = cata zalg
where
zalg x = alg x <<< project
update :: forall a. [a] -> Natural -> a -> [a]
update xs n a = zipo alg n xs
where
alg :: Maybe ([a] -> [a]) -> ListF a [a] -> [a]
alg _ Nil = []
alg Nothing (Cons y ys) = a:ys
alg (Just n') (Cons y ys) = y:(n' ys)
Also u can implement some parallel version like
zipCata :: (Recursive g, Recursive h) => ((g -> h -> r) -> Base g g -> Base h h -> r) -> g -> h -> r
zipCata phi x y = phi (zipCata phi) (project x) (project y)
update' :: forall a. [a] -> Natural -> a -> [a]
update' xs n a = zipCata alg n xs
where
alg :: (Natural -> [a] -> [a]) -> Maybe Natural -> ListF a [a] -> [a]
alg _ _ Nil = []
alg _ Nothing (Cons _ ys) = a:ys
alg f (Just n) (Cons y ys) = y:(f n ys)
Both variants (also as your) will be get the same result
PS. I hate approach for code sample on SO

A map function that operates on pairs

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

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

"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