我想创建一个固定长度(例如4)的元素序列([0,1]),这样它就会得到一个包含[0,1]所有组合的元素列表列表。
我使用命令式编程方法解决了它:
Prelude > let base = [1, 0]
Prelude > [[x0, x1, x2, x3] | x0 <- base, x1 <- base, x2 <- base, x3 <- base]
[[1,1,1,1],[1,1,1,0],[1,1,0,1], ... [0,0,0,0]]
我认为这是可以改进的。
这样做的惯用方法是什么?
答案 0 :(得分:7)
sequence
有效:
Prelude> sequence (replicate 4 [1,0])
[[1,1,1,1],[1,1,1,0],[1,1,0,1],[1,1,0,0],[1,0,1,1],[1,0,1,0],[1,0,0,1],[1,0,0,0],[0,1,1,1],[0,1,1,0],[0,1,0,1],[0,1,0,0],[0,0,1,1],[0,0,1,0],[0,0,0,1],[0,0,0,0]]
但序列和复制的配对已有一个名称:
Prelude> import Control.Monad
Prelude Control.Monad> replicateM 4 [1,0]
[[1,1,1,1],[1,1,1,0],[1,1,0,1],[1,1,0,0],[1,0,1,1],[1,0,1,0],[1,0,0,1],[1,0,0,0],[0,1,1,1],[0,1,1,0],[0,1,0,1],[0,1,0,0],[0,0,1,1],[0,0,1,0],[0,0,0,1],[0,0,0,0]]
由于sequence
正在完成所有有趣的工作,请让我们仔细研究一下。
sequence :: Monad m => [m a] -> m [a]
sequence [] = return []
sequence (x:xs) = do
x' <- x
xs' <- sequence xs
return (x':xs')
(有更短的方式来写,但这是最直接的。)
事实证明sequence
不包含任何有趣的逻辑。这是该类型签名中唯一使用其全部参数的明显函数。因此,真正的魔力必须在Monad
的{{1}}实例中,我猜。
[]
这只是推卸责任到instance Monad [] where
return x = [x]
xs >>= f = concatMap f xs
- 但也许它现在开始变得更有意义..
concatMap
我不确定这有多大帮助,但值得记住。
可能更有帮助的是将concatMap :: (a -> [b]) -> [a] -> [b]
concatMap _ [] = []
concatMap f (x:xs) = f x ++ concatMap f xs
的类型签名专门化为sequence
:
m ~ []
在这种特定情况下,sequence :: [[a]] -> [[a]]
实际上可能更好地重命名为sequence
。它创建了所有序列,包括从每个内部列表中选择一个元素。