使用list monad实现每位数的计数器

时间:2009-12-06 18:02:50

标签: haskell list-comprehension monads

所以,我正在研究问题here,并针对这个问题构建了一个相当丑陋的解决方案。在尝试清理时,我开始调查列表推导和列表monad。我决定要做的是使用list monad实现一个每位数的计数器。给定一个数字输入序列[1, 2],我想生成一个类似于:

的输出序列
[ [ 0, 0],
  [ 0, 1 ],
  [ 0, 2 ],
  [ 1, 0 ],
  [ 1, 1 ],
  [ 1, 2 ] ]

也就是说,我会遍历该范围内列表中所有元素的所有可能值。

haskell.org list monad documentation说:

  

绑定函数应用于输入列表中的所有可能值,并将结果列表连接起来以生成所有可能结果的列表。

大!看起来很完美......这是我为编写解决方案而编写的代码:

count :: [Integer] -> [[Integer]]
count [] = []
count (x:xs) =
  -- get all possible sequences for the remaining digits
  let
    remDigits :: [[Integer]]
    remDigits = count xs
  in
  -- pull out a possible sequence for the remaining digits
  do nextDigits <- remDigits
     -- pull out all possible values for the current digit
     y <- [0..x]
     -- record that "current digit" : "remaining digits" is
     -- a valid output.
     return (y:nextDigits)

但是用任何东西调用count会产生空列表,我不知道为什么。我错过了什么?

4 个答案:

答案 0 :(得分:8)

count = sequence . map (enumFromTo 0)

是的,它真的很简单。试一试:)

答案 1 :(得分:8)

更短

count = mapM (enumFromTo 0)

答案 2 :(得分:3)

为了完整性,您还可以将逻辑表达为列表理解,这可能是使用list monad进行简单函数的最佳方法:

count (x:xs) = [ (y:ys) | y <- [0..x], ys <- count xs ]

答案 3 :(得分:2)

首先,您需要将单例列表作为参数的基本案例。试试这个:

count :: [Integer] -> [[Integer]]
count [] = []
count [n] = map (\x -> [x]) [0..n]
count (x:xs) =
     do y <- [0..x]
        nextDigits <- count xs
        return (y:nextDigits)

 main = do
   print $ count [1]
   print $ count [1,2]