I am trying to implement a function (described below) that takes two lists (each or both may be infinite) and return a list of tuples of all the possible pairs of elements between the lists
zipInf :: [a] -> [b] -> [(a,b)]
(e.g the output should be like this, but doesn't have to be exactly like this)
zipInf [0 .. 2] ['A' .. 'C'] ~> [(0,'A'),(1,'A'),(0,'B'),(1,'B'),(0,'C'),(2,'A'),(2,'B'),(1,'C'),(2,'C')]
zipInf [] [0 ..] ~> []
zipInf [0 ..] [] ~> []
take 9 (zipInf ['A'] [0 .. ]) ~> [('A',0),('A',1),('A',2),('A',3),('A',4),('A',5),('A',6),('A',7),('A',8)]
I've started implementing it like this:
zipInf :: [a] -> [b] -> [(a,b)]
zipInf [] _ = []
zipInf _ [] = []
zipInf
I wanted to feed the list into a helper function to produce the lists but the one I made fails to compile and don't know how to handle infinite lists
Helper function-
oneList :: [a] -> [b] [(a,b)]
oneList [] _ = []
oneList x:xs y:ys = [(x,y)] ++ oneList
This is a great exercise!
If we lay out the pairs of your input in an infinite table:
(0,A) (1,A) (2,A) (3,A) ...
(0,B) (1,B) (2,B) (3,B) ...
(0,C) (1,C) (2,C) (3,C) ...
(0,D) (1,D) (2,D) (3,D) ...
...
The trick is to traverse the table in upward diagonal stripes. Trace the table with your eyes. The stripes of this table are:
(0,A)
(0,B) (1,A)
(0,C) (1,B) (2,A)
(0,D) (1,C) (2,B) (3,A)
...
All the stripes are finite, yet every element of the table is in one of them, so if you concatenate them together every element will appear at a finite position in the concatenated result.
Here's the gameplan I'd suggest:
Implement stripes :: [[a]] -> [[a]]
which extracts the list of stripes from an infinite array like above (start by assuming that all lists are infinite, i.e. don't worry about the []
cases; once you have that working, correct it to work on lists that might be finite).
Using stripes
, implement diagonal :: [[a]] -> [a]
which concatenates all the stripes (this is a one-liner).
Finally, implement your function by applying diagonal
of a particular 2D table [[(a,b)]]
, which is the table I started this answer with (and can be constructed using a nested list comprehension, among other various ways).
Notes:
The name zip is misleading. This is more like a cartesian product.
You know you can match patterns inside patterns, right? I.e. if f :: [[a]] -> something
f ((x:xs):xss) = ...
Gives you x
as the first element of the first row, xs
is the rest of the first row, and xss
is the rest of the table.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With