You pronounce this combination pattern of <$>
and <*>
as liftA2
:
liftA2 :: Applicative f
=> (a -> b -> c) -> f a -> f b -> f c
So then in your case f ~ []
, (+) :: Num a => a -> a -> a
, and
liftA2 :: Num a
=> (a->a->a) -> [a] -> [a] -> [a]
-- (+) ...
(+) <$> [x,0] <*> allSums xs
=
[(x +), (0 +)] <*> allSums xs
=
liftA2 (+) [x,0] (allSums xs)
=
[x + r | x <- [x,0], r <- allSums xs]
and what they "do" in the case of lists is to form the Cartesian product-like combinations of the constituents and apply the function to each of the combinations.
In your case of summing the elements, using 0
for an element is like skipping over it completely. Thus indeed implementing the sums of the power set of numbers:
allSums [x1, x2, ..., xn]
=
[x1 + r | x1 <- [x1,0], r <- allSums [x2, ..., xn]]
=
[x1 + r | x1 <- [x1,0], r <- [x2 + r | x2 <- [x2,0], r <- allSums [x3, ..., xn]]]
=
[x1 + x2 + r | x1 <- [x1,0], x2 <- [x2,0], r <- allSums [x3, ..., xn]]
=
...
=
[x1 + x2 + ... + xn + r | x1 <- [x1,0], x2 <- [x2,0], ..., xn <- [xn,0], r <- [0]]
=
[x1 + x2 + ... + xn | x1 <- [x1,0], x2 <- [x2,0], ..., xn <- [xn,0]]
As to the pronunciation, I read (+) <$> [x, 0] <*> allSums xs
as "plus over x
-and-0 over all sums of x
es".
As Daniel Wagner comments under the question, [x, 0]
could be tweaked into [x | x /= 0] ++ [0]
, for efficiency.