关于我的第一个haskell计划的问题

时间:2010-10-19 07:52:28

标签: haskell

程序返回'0'和'1'长度为N的所有可能组合。

addToElement :: String -> String -> String
addToElement element symbol = element ++ symbol

addOneToElement :: String -> String
addOneToElement element = addToElement element "1"                

addZeroToElement :: String -> String
addZeroToElement element = addToElement element "0"                

processListOnce :: [String] -> [String]
processListOnce lst = do
    let s1 = map addOneToElement lst
    let s2 = map addZeroToElement lst 
    s1 ++ s2

processList :: [String] -> Integer -> [String]
processList lst 1 = processListOnce lst
processList lst n = do
             let tmp = processListOnce(lst)
             processList tmp (n - 1)

{-                       
processList2 :: [String] -> Integer -> [String]
processList2 lst n = iterate (map processListOnce) lst !! n
-}

main = do
     let s = processList ["0", "1"] 2
     let ss = show s
     putStrLn ss

这是我的第一个Haskell计划,所以如果你帮助我,我将感激不尽:

  • 首先请重构我的代码Haskell-way。我已经知道一个神奇的refactring:

     Control.Monad.replicateM n [0,1]
    

    但这种解决方案不适合学习目的:)

  • 为什么我不能使用ProcessList2代替ProcessList并获取错误:

    all_possible_combinations.hs:44:51:
    Couldn't match expected type `[Char]' against inferred type `Char'
    Expected type: [String]]
    Inferred type: [String]
    In the second argument of `iterate', namely `lst'
    In the first argument of `(!!)', namely
     `iterate (map processListOnce) lst'
    
    • 有没有办法跳过(不使用)processList中的'tmp'变量?我试过了,但得到了错误:

      processList :: [String] -> Integer -> [String]
      processList lst 1 = processListOnce lst
      processList lst n = processList processListOnce(lst) (n - 1)
      
      
      all_possible_combinations.hs:39:32:
      Couldn't match expected type `[String]'
      against inferred type `[String] -> [String]'
      In the first argument of `processList', namely `processListOnce'
      In the expression: processList processListOnce (lst) (n — 1)
      In the definition of `processList':
      processList lst n = processList processListOnce (lst) (n — 1)
      

提前致谢。

4 个答案:

答案 0 :(得分:9)

  

首先请重构我的代码Haskell-way。我已经知道一个神奇的refactring:

Control.Monad.replicateM n [0,1]
     

但这种解决方案不适合学习目的:)

实际上,虽然我当然不希望有新的Haskell想出这样的解决方案,但我认为理解这个版本对非常有利于学习目的。

常规replicate函数非常简单:它会重复创建一个重复相同元素的列表。这也是replicateM所做的第一步:

> replicate 2 ["0", "1"]
[["0", "1"], ["0", "1"]]

replicateM所做的第二步是根据元素的Monad对序列进行“排序”,将一个monadic值列表[m a]转换为monadic值列表m [a]。这样做是在某种意义上“结合”每个monadic值的结构,其中“combine”的具体含义取决于特定的monad。

作为Monad,列表代表尝试多种可能性之类的内容。因此,当我们“排序”这些值时,这意味着每一步都会分别尝试所有可能性,并收集所有可能的结果。

因此,["0", "1"]是一个monadic值,表示尝试两种不同的可能性。 [["0", "1"], ["0", "1"]]是重复两次的monadic值的列表。为了对该列表进行排序,我们从列表的第一个元素中获取每种可能性,将其用作结果列表的头部,然后继续直到结束。因为每组可能性是相同的,所以最终结果是每个可能项目的所有可能组合:

> replicateM 2 ["0", "1"]
[["0","0"],["0","1"],["1","0"],["1","1"]]

答案 1 :(得分:8)

关于制作Haskelly,这里的解决方案不是纯粹的魔法(因为复制M可能是)

onesAndZeroes 0 = [[]]
onesAndZeroes n = [x:xs | x <- [0,1], xs <- onesAndZeroes (n-1)]

由于您不熟悉haskell,如果您不了解它,可能有助于阅读list comprehensions

答案 2 :(得分:5)

  

有没有办法在processList中跳过(不使用)'tmp'变量?我试过了,但得到了错误:

此定义使用了错误的优先级。你应该写

processList lst n = processList (processListOnce lst) (n - 1)
-- #                            ^                   ^
  

为什么我不能使用ProcessList2代替ProcessList并获取错误:

processListOnce已经是[String] -> [String]功能。如果您使用map processListOnce,它将成为[[String]] -> [[String]]函数。因此,请删除map

processList2 lst n = iterate processListOnce lst !! n

答案 3 :(得分:0)

另一种解决方案:

onesAndZeroes n = combo n ["0", "1"]
    where combo 1 cs = cs
          combo n cs = combo (n-1) (f cs)
          f = concatMap (\x -> ['0':x, '1':x])

和其他人一样,我认为replicateM将是我的第一选择,但如果我要避免这样做,那将是我的解决方案。也许不如列表理解解决方案清晰/简洁,但我发现尾调用递归非常优雅。