例如,list = [1,2,3,4]
。 listProduct list
返回[1,2,3,4,6,8,9,12,16]
,即[(1*1),(1*2),(1*3),(1*4),(2*3),(2*4),(3*3),(3*4),(4*4)]
我记得看到有些东西可以做到这一点,但我再也找不到那个资源了。
答案 0 :(得分:9)
您可以使用列表解析以简单的方式编写此代码:
listProduct xs = [x * y | x <- xs, y <- xs]
但是,使用list monad更加惯用:
import Control.Monad
listProduct = join $ liftM2 (*)
(相当于listProduct xs = liftM2 (*) xs xs
)
要理解此版本,您可以将liftM2
视为一种广义Cartesian product(liftM2 (,)
是笛卡尔积本身)。如果将liftM2
的定义专门化为列表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
因此listProduct
的monadic定义扩展为:
listProduct xs = concatMap (\x -> map (x *) xs) xs
(请注意,从技术上讲,您不需要这里的完整列表monad;所需的只是列表的Applicative
实例,而listProduct = join $ liftA2 (*)
也可以正常工作。但是,它更容易显示如何使用monadic定义,因为列表的Applicative
实例是根据Monad
实例定义的。)
答案 1 :(得分:5)
为什么您的示例不在结果中包含2*2
?
如果是因为它与1*4
相同---也就是说,你不需要重复 - 那么
listProduct xs = nub [x * y | x <- xs, y <- xs]
另一方面,如果你想要重复 - 如果你想将每个数字乘以列表中的每个后续数字,并在结果中包含重复数据---那么
listProduct' xs = triangularAutoZipWith (*)
triangularAutoZipWith op = concatMap f . tails
where f [] = []
f xs @ (x : _) = map (op x) xs
您可以在第一个解决方案的更高效版本中使用triangularAutoZipWith
:
listProduct = nub . triangularAutoZipWith (*)
答案 2 :(得分:4)
使用...
import Control.Applicative
......有重复...
listProduct list = (*) <$> list <*> list
......没有......
listProduct list = concat (mul <$> list <*> list) where
mul a b | a <= b = [a*b]
| otherwise = []
如果你处于rube-goldberg心情,你可以使用......
listProduct list = concat $ zipWith (map.(*)) list (map ((`filter` list).(<=)) list)
......或者只是......
import Data.List
listProduct list = concat $ zipWith (map.(*)) list $ tails list
<强> [编辑] 强>
另一种方法是使用sequence
。有重复:
listProduct = map product . sequence . replicate 2
不
listProduct = map product . filter(\[a,b] -> a <= b) . sequence . replicate 2
答案 3 :(得分:1)
嗯,你已经得到了一些答案,但我会打算扔进去,因为我认为早期的答案虽然准确,但可能没有多大帮助。
初学者理解的最简单的解决方案是列表理解:
example1 = [ x*y | x <- list, y <- list ]
这种语法存在于Python等一些流行语言中,在任何情况下都应该易于理解:“其元素是x*y
结果的列表,其中x
是{{1}的元素}和list
是y
的元素。“您还可以在列表推导中添加条件以过滤掉某些组合,例如,如果您不希望产品位于list
:
x == y
更复杂的答案与列表推导等同于 List Monad 的事实有关;列表类型的标准example2 = [ x*y | x <- list, y <- list, x /= y ]
类型类的实现。这意味着Monad
也可以通过以下方式实现:
example1
example1' = do x <- list
y <- list
return (x*y)
- 符号只是语法糖:
do
Landei的答案是基于以下事实:如果你没有在列表理解中使用任何条件,只有Cartesian产品,你就可以使用弱于{{1的example1'' = list >>= (\x -> list >>= (\y -> return (x*y)))
类型类。 }}