Reputation: 13908
The title of this question might sound misleading, but I wasnt sure how else to explain what I'm trying to do.
I'm experimenting with non-deterministic data structures. I'm trying to produce all possible combinations of a set of partially apply operators and a list of tuples:
-- test.hs
makeTupleList :: (Int, Int) -> [(Int, Int)]
makeTupleList (a, b) = ZipList [(+2), (-2)] <*> ZipList [a, b]
I want makeTupleList
to return something like:
[(a + 2, b + 2), (a + 2, b - 2), (a - 2, b + 2), (a - 2, b - 2)]
But I'm clearly doing something wrong because I keep getting this error:
Couldn't match type `ZipList' with `[]'
How do I get my desired result?
Upvotes: 1
Views: 255
Reputation: 464
I would drop the ZipList:
makeTupleList :: (Int, Int) -> [(Int, Int )]
makeTupleList (a,b) = (,) <$> aList <*> bList
where
functionList :: [Int -> Int]
functionList = [flip (-) 2 ,(+ 2) ]
aList :: [Int]
aList = functionList <*> [a]
bList = functionList <*> [b]
Yielding:
λ> makeTupleList (1,1)
[(-1,-1),(-1,3),(3,-1),(3,3)]
ZipList is for not generating permutations out of an applicative action.
Upvotes: 4
Reputation: 38893
There's a mismatch between the type you declared and the type the function actually has.
Let's just check the body of the function
*> :t \(a, b) -> ZipList [(+2), (-2)] <*> ZipList [a, b]
\(a, b) -> ZipList [(+2), (-2)] <*> ZipList [a, b]
:: (Num (b -> b), Num b) => (b, b) -> ZipList b
Eep! That's not good at all.
So let's fix the error. The first error is that -2
trips you up, because it parses as negative two, not an operator section.
You can see that by typechecking just that fragment:
*> :t (-2)
(-2) :: Num a => a
Ok, so we'll change it to an explicit lambda, and get closer:
*> :t \(a, b) -> ZipList [(+2), (\x -> x - 2)] <*> ZipList [a, b]
\(a, b) -> ZipList [(+2), (\x -> x - 2)] <*> ZipList [a, b]
:: Num b => (b, b) -> ZipList b
Now we see the conceptual error (you can see even more if you test it). We're just getting back [a+2,b-2]
. That's what ziplist does -- "zips" the lists together. It doesn't take the cross product.
So now we see we're on the completely wrong track.
When we want to take a "producty" combination, I find the most natural way is to use a list comprehension. So let's just do that instead.
makeTupleList (a,b) = let funs = [(+2),(\x->x-2)]
in [(f a, g b) | f <- funs, g <- funs]
And that seems to do it.
*> makeTupleList (10,20)
[(12,22),(12,18),(8,22),(8,18)]
Upvotes: 4