This has to be dead simple and I'm unhappy I can't figure it out at this point in my Haskell experience. I want a cartesian product of a list with itself, but I want to filter out identical items. I don't want a post filter.
This gets me the CP - seemingly set up to simply add a filter...
p as bs = do
a <- as
b <- bs
return (a,b)
p [1,2,3] [1,2,3]
[(1,1),(1,2),(1,3),(2,1),(2,2),(2,3),(3,1),(3,2),(3,3)]
I have read that return () is basically a noop in do notation - but this doesn't compile. (Are the tuples being mixed up)
pf as bs = do
a <- as
b <- bs
if a == b then return () else return (a,b)
* Couldn't match type `()' with `(a, a)'
Expected type: [(a, a)]
Actual type: [()]
I have tried a few other things, like the if' function from the Haskell wiki. I also tried when without success. When the filter is when
when (a /= b) return (a,b)
* Couldn't match type `m0 (a, a)' with `()'
Expected type: (a, a) -> ()
Actual type: (a, a) -> m0 (a, a)
I suppose these error messages are leading me by the nose to the issue but I am not adept at translating most of them yet.
There is very possibly a higher level function that might handle this in a more straight forward way (filterM ?), and I'll be happy to hear about its usage, but I still want to know how to solve this issue in the pf function above.
Thanks
CodePudding user response:
Try:
module Main where
main :: IO ()
main = print $ p [1,2,3] [1,2,3] -- [(1,2),(1,3),(2,1),(2,3),(3,1),(3,2)]
p as bs =
do
a <- as
b <- bs
if a == b then [] else return (a, b)
I've learned Haskell a bit only recently, so I may be wrong. In this context, return (a, b) is nothing more than the expression [(a, b)] (which is natural, since for monad [] you need a function with the output of type [t]). So you need to provide the same type, i.e., the empty list [].
On the other hand when you write return () it actually is [()], whose type is [()], which is not the same as, say, the type [(Int, Int)].
CodePudding user response:
You can also use Control.Monad.guard instead of using [] directly.
import Control.Monad (guard)
p as bs =
do
a <- as
b <- bs
guard $ a /= b
return (a, b)
You can think this as a do-notation version of the list-comprehension [(a, b) | a <- as, b <- bs, a /= b].
