List1 = [a,b]
List2 = [1,2]
I want the result list to look like this [a1, b2]
Currently i have:
[(v,a) | v <- List1, a <- List2 ]
but that gives [a1, a2, b1, b2]
What you need is zip :: [a] -> [b] -> [(a, b)]. This iterates concurrently over the two lists, and makes 2-tuples for these items.
For example:
Prelude> zip ['a', 'b'] [1,2]
[('a',1),('b',2)]
Prelude> zip [1,4,2,5] "bacd"
[(1,'b'),(4,'a'),(2,'c'),(5,'d')]
zip will stop from the moment that one of the two lists is exhausted. So if one of the lists is infinite, and the other is finite, then the result will be a finite list for example.
You can also make use of the ParallelListComp extension to iterate over collections in parallel in a list comprehension expression:
{-# LANGUAGE ParallelListComp #-}
myzip :: [a] -> [b] -> [(a, b)]
myzip la lb = [(a, b) | a <- la | b <- lb ]
but here it does not make much sense to do that. If you want to do more "complex" zipping, then this extension is probably more useful.
So, you want a function of type [Char] -> [Int] -> [(Char, Int)]. Let me introduce you to Hoogle:
zip :: [a] -> [b] -> [(a, b)]
base Prelude Data.List GHC.List GHC.OldList, Cabal Distribution.Compat.Prelude.Internal, ghc GhcPrelude
. zip takes two lists and returns a list of corresponding pairs.
zip [1, 2] ['a', 'b'] = [(1, 'a'), (2, 'b')]
If one input list is short, excess elements of the longer list are discarded:
zip [1] ['a', 'b'] = [(1, 'a')]
zip [1, 2] ['a'] = [(1, 'a')]
zip is right-lazy:
zip [] _|_ = []
zip _|_ [] = _|_
zip is capable of list fusion, but it is restricted to its first list argument and its resulting list.
zip :: () => [a] -> [b] -> [(a, b)]
hspec Test.Hspec.Discover, base-compat Prelude.Compat, protolude Protolude, rio RIO.List RIO.Prelude, universum Universum.List.Reexport, dimensional Numeric.Units.Dimensional.Prelude, rebase Rebase.Prelude, ghc-lib-parser GhcPrelude, xmonad-contrib XMonad.Config.Prime, stack Stack.Prelude, LambdaHack Game.LambdaHack.Core.Prelude Game.LambdaHack.Core.Prelude, mixed-types-num Numeric.MixedTypes.PreludeHiding, heart-core Heart.Core.Prelude, intro Intro, hledger-web Hledger.Web.Import, tonalude Tonalude, brittany Language.Haskell.Brittany.Internal.Prelude
zip takes two lists and returns a list of corresponding pairs.
zip [1, 2] ['a', 'b'] = [(1, 'a'), (2, 'b')]
If one input list is short, excess elements of the longer list are discarded:
zip [1] ['a', 'b'] = [(1, 'a')]
zip [1, 2] ['a'] = [(1, 'a')]
zip is right-lazy:
zip [] _|_ = []
zip _|_ [] = _|_
zipExact :: Partial => [a] -> [b] -> [(a, b)]
safe Safe.Exact
zipExact xs ys =
| length xs == length ys = zip xs ys
| otherwise = error "some message"
zip :: () => [a] -> [b] -> [(a, b)]
numeric-prelude NumericPrelude NumericPrelude.Base, distribution-opensuse OpenSuse.Prelude
zip takes two lists and returns a list of corresponding pairs. If one input list is short, excess elements of the longer list are discarded. zip is right-lazy:
zip [] _|_ = []
(+*+) :: [a] -> [b] -> [(a, b)]
universe-base Data.Universe.Helpers
cartesianProduct (,)
...
The first hit
One other way can also be achieved by the ZipList type which is defined in Control.Applicative to lower the undeterministic approach to a simpler one to one mapping for the List types.
All you need is to import Control.Applicative and use the ZipList data constructor.
λ> getZipList $ (,) <$> ZipList "ab" <*> ZipList [1,2]
[('a',1),('b',2)]
getZipList is an accessor which extracts a proper list from the ZipList type.
Related
Consider the following function:
(<.>) :: [[a]] -> [[a]] -> [[a]]
xs <.> ys = zipWith (++) xs ys
This essentially takes two two-dimensional arrays of as and concatanates them, left to right, e.x.:
[[1,2],[3,4]] <.> [[1,2],[3,4]] == [[1,2,1,2],[3,4,3,4]]
I would like to be able to write something like the following:
x = foldr1 (<.>) $ repeat [[1,2],[3,4]]
Which should make sense due to Haskell's lazy evaluation, i.e. we should obtain:
x !! 0 == [1,2,1,2,1,2,1,2...]
x !! 1 == [3,4,3,4,3,4,3,4...]
However, when I try to run this example with GHCi, either using foldr1 or foldl1, I either get a non-terminating computation, or a stack overflow.
So my question is:
What's going on here?
Is it possible to do what I'm trying to accomplish here with some function other than foldr1 or foldl1? (I'm happy if I need to modify the implementation of <.>, as long as it computes the same function)
Also, note: I'm aware that for this example, map repeat [[1,2],[3,4]] produces the desired output, but I am looking for a solution that works for arbitrary infinite lists, not just those of the form repeat xs.
I'll expand on what's been said in the comments here. I'm going to borrow (a simplified version of) the GHC version of zipWith, which should suffice for the sake of this discussion.
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWith f [] _ = []
zipWith f _ [] = []
zipWith f (x:xs) (y:ys) = f x y : zipWith f xs ys
Now, here's what your computation ends up looking like, in it's glorious infinite form.
[[1, 2], [3, 4]] <.> ([[1, 2], [3, 4]] <.> ([[1, 2], [3, 4]] ... ) ... )
Okay, so the top-level is a <.>. Fine. Let's take a closer look at that.
zipWith (++) [[1, 2], [3, 4]] ([[1, 2], [3, 4]] <.> ([[1, 2], [3, 4]] ... ) ... )
Still no problems yet. Now we look at the patterns for zipWith. The first pattern only matches if the left-hand-side is empty. Welp, that's definitely not true, so let's move on. The second only matches if the right-hand-side is empty. So let's see if the right-hand-side is empty. The right-hand-side looks like
[[1, 2], [3, 4]] <.> ([[1, 2], [3, 4]] <.> ([[1, 2], [3, 4]] ... ) ... )
Which is what we started with. So to compute the result, we need access to the result. Hence, stack overflow.
Now, we've established that our problem is with zipWith. So let's play with it. First, we know we're going to be applying this to infinite lists for our contrived example, so we don't need that pesky empty list case. Get rid of it.
-- (I'm also changing the name so we don't conflict with the Prelude version)
zipWith' :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWith' f (x:xs) (y:ys) = f x y : zipWith' f xs ys
(<.>) :: [[a]] -> [[a]] -> [[a]]
xs <.> ys = zipWith' (++) xs ys
But that fixes nothing. We still have to evaluate to weak head normal form (read: figure out of the list is empty) to match that pattern.
If only there was a way to do a pattern match without having to get to WHNF... enter lazy patterns. Let's rewrite our function this way.
zipWith' :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWith' f ~(x:xs) ~(y:ys) = f x y : zipWith' f xs ys
Now our function will definitely break if given a finite list. But this allows us to "pretend" pattern match on the lists without actually doing any work. It's equivalent to the more verbose
zipWith' :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWith' f xs ys = f (head xs) (head ys) : zipWith' f (tail xs) (tail ys)
And now we can test your function properly.
*Main> let x = foldr1 (<.>) $ repeat [[1, 2], [3, 4]]
*Main> x !! 0
[1,2,1,2,1,2,1,2,1,...]
*Main> x !! 1
[3,4,3,4,3,4,3,4,3,...]
The obvious downside of this is that it will definitely fail on finite lists, so you have to have a different function for those.
*Main> [[1, 2], [3, 4]] <.> [[1, 2], [3, 4]]
[[1,2,1,2],[3,4,3,4],*** Exception: Prelude.head: empty list
zipWith is not -- in fact, it can't possibly be -- as lazy as you'd like. Consider this variation on your example:
GHCi> foldr1 (zipWith (++)) [ [[1,2],[3,4]], [] ]
[]
Any empty list of lists in the input will lead to an empty list of lists result. That being so, there is no way to know any of the elements of the result until the whole input has been consumed. Therefore, your function won't terminate on infinite lists.
Silvio Mayolo's answer goes through some potential workarounds for this issue. My suggestion is using non-empty-lists of lists, instead of plain lists of lists:
GHCi> import qualified Data.List.NonEmpty as N
GHCi> import Data.List.NonEmpty (NonEmpty(..))
GHCi> take 10 . N.head $ foldr1 (N.zipWith (++)) $ repeat ([1,2] :| [[3,4]])
[1,2,1,2,1,2,1,2,1,2]
N.zipWith doesn't have to deal with an empty list case, so it can be lazier.
Basically I have this exercise:
Using list comprehensions, write a polymorphic function:
split :: [(a, b)] -> ([a], [b])
which transforms a list of pairs (of any types) into a pair of lists. For example,
split [(1, 'a'), (2, 'b'), (3, 'c')] = ([1, 2, 3], "abc")
This was the way I wrote the function but it is not working:
split :: [(a, b)] -> ([a], [b])
split listOfPairs = (([a | a <- listOfPairs]), ([b | b <- listOfPairs]))
Can someone please explain why my solution doesn't work? Thank you!
A list comprehension like:
[a | a <- listOfPairs]
is actually nothing more than an identity operation for lists. It will yield the same list as the one you provide, since you basically iterate over listOfPairs, and for each iteration, you yield the element a.
Haskell does not perform implicit conversions, so it does not derive from the types that a in your a <- listOfPairs then only can be the first element. Even if that was possible, it was probably not a good idea anyway, since it would make the language more "unstable" in the sense that a small change in the types, could have significant impact in the semantics.
In order to obtain the first element of a tuple, you need to use pattern matching, like:
[a | (a, _) <- listOfPairs]
here we thus pattern match the first element of the tuple with a, and for the second one, we thus use:
[b | (_, b) <- listOfPairs]
We can thus impelement this as:
split:: [(a,b)] -> ([a],[b])
split listOfPairs = ([a | (a, _) <- listOfPairs], [b | (_, b) <- listOfPairs])
Or we can use map :: (a -> b) -> [a] -> [b], fst :: (a, b) -> a and snd :: (a, b) -> b:
split:: [(a,b)] -> ([a],[b])
split listOfPairs = (map fst listOfPairs, map snd listOfPairs)
But the above still has a problem: here we iterate twice independently over the same list. We can omit that by using recursion, like:
split:: [(a,b)] -> ([a],[b])
split [] = []
split ((a, b):xs) = (a:as, b:bs)
where (as, bs) = split xs
or we can use a foldr function:
split :: Foldable f => f (a,b) -> ([a],[b])
split = foldr (\(a,b) (as,bs) -> (a:as,b:bs)) ([],[])
There is already a Haskell function that does exactly what you want: unzip :: [(a, b)] -> ([a], [b]), with the source code.
I can't figure out how to implement the map and filter function for a matrix. Does anyone have any suggestions that would satisfy these tests?
-- | Matrix Tests
--
-- prop> mapMatrix (\a -> a - 3) (mapMatrix (+ 3) x) == x
--
-- >>> filterMatrix (< 3) matrix1
-- [[1,2],[2]]
-- >>> filterMatrix (> 80) []
-- []
-- >>> transpose' matrix2
-- [[1,4],[5,8]]
mapMatrix :: (a -> b) -> [[a]] -> [[b]]
mapMatrix f [list] = [map f list]
filterMatrix :: (a -> Bool) -> [[a]] -> [[a]]
filterMatrix = undefined
transpose' :: [[a]] -> [[a]]
transpose' = undefined
matrix1 = [[1 .. 10], [2 .. 20]]
matrix2 = [[1, 5], [4, 8]]
Some hints, but not a complete solution because this sounds like homework. mapmatrix and filterMatrix: write functions that work on one row of your matrix at a time, then map those onto the list of rows. transpose': one way to do this would be with a list comprehension that applies the !! operator to lists of indices, and another would be a recursive function that removes one row at a time from the input and adds one column at a time to the output.
Is filterMatrix supposed to return a list of lists that is not a valid matrix?
I'm working on a piece of code where I have to process lists of tuples where both the order and names of the "keys" (fsts of the tuples) match a certain template. I'm implementing fault tolerance by validating and (if needed) generating a valid list based on the input.
Here's an example of what I mean:
Given the template of keys, ["hello", "world", "this", "is", "a", "test"], and a list [("hello", Just 1), ("world", Just 2), ("test", Just 3)], passing it to my function validate would cause it to fail validation - as the order and values of the keys do not match up with the template.
Upon failing validation, I want to generate a new list, which would look like [("hello", Just 1), ("world", Just 2), ("this", Nothing), ("is", Nothing), ("a", Nothing), ("test", Just 3)].
I tried performing this last step using an (incomplete) list comprehension:
[(x, y) | x <- template, y <- l]
(Obviously, this is missing the step where empty entries would be replaced with Nothings, and works under the assumption that the input is of type [(String, Maybe Int)]).
What would be the easiest semantic way of doing this?
You essentially want to map a function to your list of strings (which you call "template"), i.e. the function that
takes a string xs,
returns
(xs, Just n) if an integer n is associated to xs in your "list to validate",
(xs, Nothing) otherwise.
Here is one possible approach:
import Data.List ( lookup )
import Control.Monad ( join )
consolidate :: [String] -> [(String, Maybe Int)] -> [(String, Maybe Int)]
consolidate temp l = map (\xs -> (xs, join $ lookup xs l)) temp
However, you will get faster lookup if you build a Map holding the key-value pairs of your association list (the "list to validate"):
import qualified Data.Map as M
import Data.Maybe (maybe)
consolidate :: [String] -> [(String, Maybe Int)] -> [(String, Maybe Int)]
consolidate temp l = map (\cs -> (cs, M.lookup cs $ fromList' l)) temp
fromList' :: Ord a => [(a, Maybe b)] -> M.Map a b
fromList' xs = foldr insertJust M.empty xs
insertJust :: Ord a => (a, Maybe b) -> M.Map a b -> M.Map a b
insertJust (xs, maybeVal) mp = maybe mp (\n -> M.insert xs n mp) maybeVal
In GHCi:
λ> let myTemplate = ["hello", "world", "this", "is", "a", "test"]
λ> let myList = [("hello", Just 1), ("world", Just 2), ("test", Just 3)]
λ> consolidate myTemplate myList
[("hello",Just 1),("world",Just 2),("this",Nothing),("is",Nothing),("a",Nothing),("test",Just 3)]
this is what I have for matrix addition in Haskell
> add :: (Num a) => [[a]] -> [[a]] -> [[a]]
> add [] [] = []
> add (x:xs) (y:ys) = zipWith (+) x y : add xs ys
add [[1,2], [3,4]] [[5,6], [7,8]] gives me [[6,8],[10,12]]
However, I am trying do with one line instead
> add :: (Num a) => [[a]] -> [[a]] -> [[a]]
> add = map ((zipWith (+))
How come the map function doesn't work?
The map function doesn't work here because you're iterating over two lists instead of one. To iterate over two lists in parallel, you use zipWith, just like you are already doing for the inner loop.
Prelude> let add = zipWith (zipWith (+))
Prelude> add [[1, 2], [3, 4]] [[5, 6], [7, 8]]
[[6,8],[10,12]]
map takes in a single list: you're trying to give it two.
Try something like:
add = zipWith (zipWith (+))