我有一组可能的颜色定义如下:
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
中的内容。
答案 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]
基本上,单线程与您的解决方案的想法相同,但重构为两个可重用的部分。