笛卡尔积导致固定长度列表(haskell方式)

时间:2015-07-02 14:40:48

标签: haskell

我想创建一个固定长度(例如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]]

我认为这是可以改进的。

这样做的惯用方法是什么?

1 个答案:

答案 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。它创建了所有序列,包括从每个内部列表中选择一个元素。