For example, list = [1,2,3,4]
. listProduct list
returns [1,2,3,4,6,8,9,12,16]
i.e [(1*1),(1*2),(1*3),(1*4),(2*3),(2*4),(3*3),(3*4),(4*4)]
I remember seeing that there was something that did this, but I can't find that resource any more.
You can write this in a simple manner using a list comprehension:
listProduct xs = [x * y | x <- xs, y <- xs]
However, it's more idiomatic to use the list monad:
import Control.Monad
listProduct = join $ liftM2 (*)
(equivalent to listProduct xs = liftM2 (*) xs xs
)
To understand this version, you can think of liftM2
as a kind of generalised Cartesian product (liftM2 (,)
is the Cartesian product itself). It's easier to see how this works if you specialise liftM2
's definition to the list monad:
liftM2 f mx my = do { x <- mx; y <- my; return (f x y) }
-- expand the do notation
liftM2 f mx my = mx >>= (\x -> my >>= (\y -> return (f x y)))
-- substitute the list monad's definition of (>>=)
liftM2 f mx my = concatMap (\x -> concatMap (\y -> [f x y]) my) mx
-- simplify
liftM2 f mx my = concatMap (\x -> map (\y -> f x y) my) mx
-- simplify again
liftM2 f mx my = concatMap (\x -> map (f x) my) mx
So the monadic definition of listProduct
expands to:
listProduct xs = concatMap (\x -> map (x *) xs) xs
(Note that you don't technically need the full list monad here; all that's required is the Applicative
instance for lists, and listProduct = join $ liftA2 (*)
would work just as well. However, it's easier to show how it works with the monadic definition, since the Applicative
instance for lists is defined in terms of the Monad
instance.)
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