可变长度与固定组合的组合

时间:2015-05-05 22:22:08

标签: haskell permutation combinatorics

我有一组可能的颜色定义如下:

data Peg = Red | Green | Blue | Yellow | Orange | Purple
         deriving (Show, Eq, Ord)
colors = [Red, Green, Blue, Yellow, Orange, Purple]

代码是这样定义的颜色组合:

type Code = [Peg]

我希望能够生成长度为len的所有可能组合的列表,这些组合可以使用定义的颜色制作。

这是我最初的想法。我还在学习,所以我甚至不确定我是否犯了一些不受支持的语法错误或结构。

allCodes :: Int -> [Code]
allCodes len = map (\p -> Code p) (permutations len)
    where
        permutations::Int->[Peg]
        permutations 0 = [[]]
        permutations n = [x:xs | x <- colors, xs <- permutations (n - 1)]

这不会编译,我收到错误:

[1 of 1] Compiling HW02             ( HW02.hs, interpreted )

HW02.hs:59:27: Not in scope: data constructor `Code'
Failed, modules loaded: none.

Code适用于我使用它的其他地方,所以我不确定这里发生了什么。我知道像replicateM这样的功能可以很容易地解决这个问题,但我只想使用Prelude中的内容。

1 个答案:

答案 0 :(得分:2)

bhelkir对该问题的评论已正确诊断出您的错误,因此我将跳过该错误。

allCodes函数的逻辑基本上是合理的(将排列与组合问题放在一边)。值得指出的一件事是,通过在Prelude中使用两个函数,可以实现相同的效果:

allCodes :: Int -> [Code]
allCodes len = sequence (replicate len colors)

将这一点跟进到堆栈底部是有益的。首先,replicate函数生成一个指定长度的列表,用相同的值填充所有位置:

replicate :: Int -> a -> [a]
replicate 0 _ = []
replicate n a | n > 0 = a : replicate (n-1) a
              | otherwise = error "replicate called with n < 0"

因此replicate 3 colors会生成一个包含三个元素的列表,所有这些元素都是colors列表。

现在,sequence功能有点神奇:

sequence :: Monad m => [m a] -> m [a]
sequence [] = return []
sequence (ma:mas) =
    do a <- ma
       as <- sequence mas
       return (a:as)

然而,当m = []时,这与:

相同
sequence' :: [[a]] -> [[a]]
sequence' [] = [[]]
sequence' (ma:mas) = [(a:as) | a <- ma, as <- sequence mas]

基本上,单线程与您的解决方案的想法相同,但重构为两个可重用的部分。