I'm not exactly sure if my nomenclature is correct here, but I was wondering if there was a zip function in Haskell that was greedy. This means that if I had
a = [1, 2, 3]
b = [4, 5]
zip' a b
#=> [(Just 1, Just 4),(Just 2, Just 5),(Just 3, Nothing)]
...where zip' is the greedy zip function, it would return a list of tuples the length of the longer list, and where the longer list has an element, but the shorter list does not Nothing is put in the respective tuple position. I am not asking how to write this, but instead was wondering if this exists as a built-in.
Here is my implementation (which is probably not great)
zip' :: [a] -> [b] -> [(Maybe a, Maybe b)]
zip' (a:xs) [] = (Just a, Nothing) : zip' xs []
zip' [] (b:ys) = (Nothing, Just b) : zip' [] ys
zip' [] _ = []
zip' (a:xs) (b:ys) = (Just a, Just b) : zip' xs ys
A greedy zip can be neatly expressed through a non-exclusive disjunction type (as opposed to Either, which is an exclusive disjunction). Two popular packages offer that. One is the minimalist, dependency-free data-or:
GHCi> import Data.Or
GHCi> :t zipOr
zipOr :: [a] -> [b] -> [Or a b]
GHCi> zipOr [1, 2, 3] [4, 5]
[Both 1 4,Both 2 5,Fst 3]
The other is these, which comes with lots of bells and whistles:
GHCi> import Data.These
GHCi> import Data.Align
GHCi> :t align
align :: Align f => f a -> f b -> f (These a b)
GHCi> align [1, 2, 3] [4, 5]
[These 1 4,These 2 5,This 3]
I believe Or a b and These a b express your intent better than (Maybe a, Maybe b) (the latter type includes (Nothing, Nothing), which a greedy zip will never produce). Still, you can express your zip' using either zipOrWith from Data.Or...
import Data.Or
zip' :: [a] -> [b] -> [(Maybe a, Maybe b)]
zip' = zipOrWith $ \xy -> case xy of
Both x y -> (Just x, Just y)
Fst x -> (Just x, Nothing)
Snd y -> (Nothing, Just y)
... or alignWith from Data.Align:
import Data.These
import Data.Align
zip' :: Align f => f a -> f b -> f (Maybe a, Maybe b)
zip' = alignWith $ \xy -> case xy of
These x y -> (Just x, Just y)
This x -> (Just x, Nothing)
That y -> (Nothing, Just y)
Data.Align, in fact, provides your function under the name of padZip.
Related
This is the code that I came upon somewhere but want to know how this works:
findIndices :: (a -> Bool) -> [a] -> [Int]
findIndices _ [] = []
findIndices pred xs = map fst (filter (pred . snd) (zip [0..] xs))
Output: findIndices (== 0) [1,2,0,3,0] == [2,4], where pred is (==0) & xs is [1,2,0,3,0]
I'll show some of my understanding:
(zip [0..] xs)
What the above line does is put indices to everything in the list. For the input given above, it would look like this: [(0,1),(1,2),(2,0),(3,3),(4,0)].
(pred . snd)
I found that this means something like pred (snd (x)). My question is, is x the list made from the zip line? I'm leaning towards yes but my guess is flimsy.
Next, is my understanding of fst and snd. I know that
fst(1,2) = 1
and
snd(1,2) = 2
How do these two commands make sense in the code?
My understanding of filter is that it returns a list of items that match a condition. For instance,
listBiggerThen5 = filter (>5) [1,2,3,4,5,6,7,8,9,10]
would give [6,7,8,9,10]
My understanding of map is that it applies a function to every item on the list. For instance,
times4 :: Int -> Int
times4 x = x * 4
listTimes4 = map times4 [1,2,3,4,5]
would give [4,8,12,16,20]
How does this work overall? I think I have been comprehensive in what I know so far but can't quite put the pieces together. Can anybody help me out?
I found that this means something like pred (snd (x)). My question is, is x the list made from the zip line? I'm leaning towards yes but my guess is flimsy.
Well pred . snd, means \x -> pred (snd x). So this basically constructs a function that maps an element x on pred (snd x).
This thus means that the expression looks like:
filter (\x -> pred (snd x)) (zip [0..] xs)
Here x is thus a 2-tuple generated by zip. So in order to know if (0, 1), (1,2), (2, 0), etc. are retained in the result, snd x will take the second element of these 2-tuples (so 1, 2, 0, etc.), and check if the pred on tha element is satisfied or not. If it is satisfied, it will retain the element, otherwise that element (the 2-tuple) is filtered out.
So if (== 0) is the predicate, then filter (pred . snd) (zip [0..] xs) will contain the 2-tuples [(2, 0), (4, 0)].
But now the result is a list of 2-tuples. If we want the indices, we somehow need to get rid of the 2-tuple, and the second element of these 2-tuples. We use fst :: (a, b) -> a for that: this maps a 2-tuple on its first element. So for a list [(2, 0), (4, 0)], map fst [(2, 0), (4, 0)] will return [2, 4].
In Haskell we like to say, follow the types. Indeed the pieces connect as if by wires going from type to corresponding type:
( first, function composition is:
(f >>> g) x = (g . f) x = g (f x)
(f >>> g) = (g . f) = \x -> g (f x)
and function composition type inference rule is:
f :: a -> b -- x :: a
g :: b -> c -- f x :: b
------------------------- -- g (f x) :: c
f >>> g :: a -> c
g . f :: a -> c
Now, )
findIndices :: (b -> Bool) -> [b] -> [Int]
findIndices pred = \xs -> map fst ( filter (pred . snd) ( zip [0..] xs ))
= map fst . filter (pred . snd) . zip [0..]
= zip [0..] >>> filter (snd >>> pred) >>> map fst
---------------------------------------------------------------------------
zip :: [a] -> [b] -> [(a, b)]
zip [0..] :: [b] -> [(Int,b)]
---------------------------------------------------------------------------
snd :: (a,b) -> b
pred :: b -> Bool
------------------------------------
(snd >>> pred) :: (a,b) -> Bool
---------------------------------------------------------------------------
filter :: (t -> Bool) -> [t] -> [t]
filter (snd >>> pred) :: [(a,b)] -> [(a,b)]
filter (snd >>> pred) :: [(Int,b)] -> [(Int,b)]
---------------------------------------------------------------------------
fst :: (a, b) -> a
map :: (t -> s) -> [t] -> [s]
map fst :: [(a,b)] -> [a]
map fst :: [(Int,b)] -> [Int]
so, overall,
zip [0..] :: [b] -> [(Int,b)]
filter (snd >>> pred) :: [(Int,b)] -> [(Int,b)]
map fst :: [(Int,b)] -> [Int]
---------------------------------------------------------------------------
findIndices pred :: [b] -> [Int]
You've asked, how do these pieces fit together?
This is how.
With list comprehensions, your function is written as
findIndices pred xs = [ i | (i,x) <- zip [0..] xs, pred x ]
which in pseudocode reads:
"result list contains i for each (i,x) in zip [0..] xs such that pred x holds".
It does this by turning the n-long
xs = [a,b,...,z] = [a] ++ [b] ++ ... ++ [z]
into
[0 | pred a] ++ [1 | pred b] ++ ... ++ [n-1 | pred z]
where [a | True] is [a] and [a | False] is [].
Let's say I have the following:
data D = A Int | B Int deriving Show
and I have a function
simplify :: [D] -> [D]
My goal is for simplify to create a new list where it will add up all values with data A (into a single value of data A) and keep the B data as is.
As an example, [A 1, A 2, A 3, B 1, A 4, B 2] would become [A 10, B 1, B 2].
I know I can do it with foldl:
A (foldl (+) 0 [x | A x <- ll]) : [B x | B x <- ll]
But this involves going through the list twice looking for constructors.
I was wondering if there was a way of using partition, where I could separate the list into those that have data A and those that do not.
This seems doable if you're okay with always having the A value ahead of the Bs.
simplify :: [D] -> [D]
simplify = uncurry (:) . foldr f (A 0, [])
where
f (A x) ((A n), acc) = (A (n+x), acc)
f b (a , acc) = (a , b:acc)
Though honestly I think the uncurry (:) is a mistake here, and your final type should be:
simplify :: [D] -> (D, [D])
You don't need partition for that, just a left fold:
import Data.List (mapAccumL)
simplify :: [D] -> [D]
simplify = f . mapAccumL g 0
where
g acc (A i) = acc `seq` (acc+i, [])
g acc b = (acc, [b])
f (acc, ys) = A acc : concat ys
I have following function:
meh :: (Functor m, Monad m) => [a] -> (a -> m b) -> m [b]
meh [] _ = return []
meh (x:xs) f = do
x' <- f x
fmap ((:) x') (meh xs f)
then I try it out in prelude as follow and I've got:
*ExerciseMonad Control.Monad> meh [3,4,5] (\x -> Just x)
Just [3,4,5]
But I do expect [Just 3, Just 4, Just 5].
To find out, what went wrong, I did substitution:
meh [3,4,5] (\x -> Just x) = Just [3,4,5]
meh (3:[4,5])] (\x -> Just x) =
Just 3 <- (\3 -> Just 3)
fmap ((:) (Just 3)) (meh [4,5] (\x -> Just x))
meh (4:[5])] (\x -> Just x) =
Just 4 <- (\4 -> Just 4)
fmap ((:) (Just 4)) (meh [5] (\x -> Just x))
meh ([5])] (\x -> Just x) =
Just 5 <- (\5 -> Just 5]
fmap ((:) (Just 5)) (meh [] (\x -> Just x))
meh [] _ = return []
--all the way back
meh ([5])] (\x -> Just x) = fmap ((:) (Just 5)) []
meh (4:[5])] (\x -> Just x) = fmap ((:) (Just 4)) [Just 5] <- result [Just 4, Just 5]
meh (3:[4,5])] (\x -> Just x) = fmap ((:) (Just 3)) [Just 4, Just 5] <- result [Just 4, Just 5]
meh [3,4,5] (\x -> Just x) = [Just 3,Just 4, Just 5]
As you can see, the substitution does not match to the right result:
Just [3,4,5] != [Just 3,Just 4, Just 5]
My question, what did I wrong with the substitution? That I've got the wrong result?
According to the type, everything works fine
meh :: (Functor m, Monad m) => [a] -> (a -> m b) -> m [b]
If you're expecting [Just 3, Just 4, Just 5] you might need something like:
meh :: (Functor m, Monad m) => [a] -> (a -> m b) -> [m b]
Or just
meh :: (Functor m) => [a] -> (a -> m b) -> [m b]
Because you don't need the monad instance if you're not going to join values.
meh' :: (Functor m, Monad m) => [a] -> (a -> m b) -> [m b]
meh' [] _ = []
meh' (x:xs) f =
(f x) : (meh' xs f)
Calling meh' [3,4,5] Just returns [Just 3, Just 4, Just 5]
Calling meh [3,4,5] Just returns Just [3,4,5]
Talking about a substitution (starting from the empty list):
meh [] _ = Just [], because meh [] _ = return [] returns an empty list wrapped into a monadic structure (in this case Maybe monad)
meh (5:[]) (\x -> Just x) = do
x' <- (\x -> Just x) 5
fmap ((:) x') (meh [] (\x -> Just x))
In this step x' <- (x -> Just x) 5 binds x' to 5. That's why meh [5] Just transforms into fmap ((:) 5) (Just []) that equals Just [5], rather than fmap ((:) (Just 5)) [] which indeed equals [Just 5]
As I commented before your type signature is wrong:
If you check the type for [Just 1, Just 2, ...] would be like [m b] not m [].
Also, you cant simplify your function to:
meh :: (Functor m, Monad m) => [a] -> (a -> m b) -> [m b]
meh l f = fmap f l
Here you have a life example
Your substitution is wrong on this step:
x' <- f x
Since you are working inside a monad you are binding (with <-) to x' the Value inside
the monad (Just in this case) so 'x'' will be 3 (4, 5, ...) not Just 3
I have been struggling with following problem for sometime. I spent many hours on the internet to find a viable algorithm in Haskell using recursive functions only but no success.
Define a recursive function funkyMap :: (a -> b) -> (a -> b) -> [a] -> [b] that takes as arguments two functions f and g and a list xs, and applies f to all elements at even positions ([0, 2..]) in xs and g to all elements at odd positions ([1, 3..]) in xs.
Example: funkyMap (+10) (+100) [1, 2, 3, 4, 5] = [(+10) 1, (+100) 2, (+10) 3, (+100) 4, (+10) 5].
To above problem, I attempted following solution, but HUGS give me compilation error "unification would give infinite type".
mapEven :: (a->a) -> [a] -> [a]
mapEven f [] = []
mapEven f (x:xs) = f x : mapOdd f xs
mapOdd :: (a->a) -> [a] -> [a]
mapOdd g [] = []
mapOdd g (x:xs) = x : mapEven g xs
funkyMap :: (a -> b) -> (a -> b) -> [a] -> [b]
funkyMap f g [] = []
funkyMap f g (x:xs) = (mapEven f x) ++ (mapOdd g xs)
Please suggest an alternate working solution.
Thanks
This line has a problem:
funkyMap f g (x:xs) = (mapEven f x) ++ (mapOdd g xs)
x is an element of the list (ie type a), while xs is another list (type [a]). But you are treating them the same. The error you are getting is because the only way to make sense of a list and an element being the same type is if it's a list of lists of lists of lists of lists...
By God's mercy, I got some inspiration and I seemed to have cracked this problem.
Please review the following solution:
h1 p q [] = []
h1 p q ((cnt, val) : xs) = (if odd cnt then (q val) else (p val) ) : h1 p q xs
funkyMap f g xs = h1 f g ( zip [0..] xs)
If I try funkyMap (+10) (+100) [1, 2, 3, 4, 5] I get [11,102,13,104,15] which is expected.
Also funkyMap (+100) (+2) [1] gives
[101]
and funkyMap (+100) (+2) [] gives
[]
Please review this solution and let me know your feedback.
Thanks
I've a simple question:
combine :: (a -> b -> c) -> [a] -> [b] -> [c]
combine f (a:as) (b:bs) = f a b : combine f as bs
combine _ _ _ = [ ]
This is recursive. Now i want to use a list comprehension to solve the same problem:
combine f (x:xs) (y:ys) = [ f x y | x <- (x:xs), y <- (y:ys) ]
But my problem is the combination of elements. I only want to combine x1 y1, x2 y2, xs ys ... not x1 y1, x1 y2, x1 ys, x2 y1, x2 y2, ......
Thank you!
What you need is a parallel list compehension. To be able to use it you need to specify a ParallelListComp pragma to the compiler:
{-# LANGUAGE ParallelListComp #-}
combine :: (a -> b -> c) -> [a] -> [b] -> [c]
combine f xs ys = [ f x y | x <- xs | y <- ys ]
Compiler desugars it to an application of zipWith:
combine :: (a -> b -> c) -> [a] -> [b] -> [c]
combine f xs ys = zipWith f xs ys
Which is actually what your function is, so:
combine :: (a -> b -> c) -> [a] -> [b] -> [c]
combine = zipWith
Since list comprehension usually gives Cartesian product, you can also try ZipList from Control.Applicative
GHCi> :m + Control.Applicative
GHCi> :info ZipList
newtype ZipList a = ZipList {getZipList :: [a]}
-- Defined in `Control.Applicative'
instance Functor ZipList -- Defined in `Control.Applicative'
instance Applicative ZipList -- Defined in `Control.Applicative'
GHCi> let combine f xs ys = getZipList $ f <$> ZipList xs <*> ZipList ys
GHCi> :t combine
combine :: (a2 -> a1 -> a) -> [a2] -> [a1] -> [a]
GHCi> combine (-) [10,9..] [1..10]
[9,7,5,3,1,-1,-3,-5,-7,-9]
GHCi>
Don't fear of ZipList, it just wraps a list, you can convert a list into ZipList and convert it back using getZipList.
This chapter in LYAH gives you some explanation about how to use it, have fun!
BTW, you can use a bare list in the example above, which gives you the Cartesian product:
GHCi> let combine1 f xs ys = f <$> xs <*> ys
GHCi> :t combine1
combine1 :: Applicative f => (a1 -> a -> b) -> f a1 -> f a -> f b
GHCi> combine (-) [10,9..1] [1..10]
[9,8,7,6,5,4,3,2,1,0,8,7,6,5,4,3,2,1,0,-1,...]
GHCi>
As you can see, there are two ways of merging two lists together, one is to think elements in a list as possible results, if you take one possible value from xs=[1,2], and another possible value from ys=[3,4] to make a tuple, you will end up with all possibilities: [(1,3),(1,4),(2,3),(2,4)], this is basically what [(x,y)| x <- xs, y <-ys] is saying. But there is also another way of merging two lists: every time you take one element simultaneously from two lists, and make a pair, until one of the list reaches its end, this is how ZipList get merged together.
this would be my poor answer
kk :: ( a -> b -> c) -> (a,b) -> c
kk f (x,y) = f x y
combineFunk :: (a -> b -> c) -> [a] -> [b] -> [c]
combineFunk f xs ys = [cs | (a,b) <- zip xs ys , let cs = kk f (a,b) ]