2010-10-19 61 views
5

程序返回“0”和“1”的长度为N的所有可能组合的问题关于我的第一个Haskell程序

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) 
      

感谢。

回答

5

Is there any way to skip (not use) the 'tmp' variable in the processList? I have tried, but got the error:

该定义使用了错误的优先顺序。你应该写

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

Why I can not use ProcessList2 instead ProcessList and get error:

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

processList2 lst n = iterate processListOnce lst !! n 
8

关于使其Haskelly,这里是一个解决方案,是不是纯粹的魔法(为replicateM而定)

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

既然你是新来的Haskell,如果你不明白,它可能有助于阅读有关list comprehensions

+0

+1漂亮的代码:-) – fortran 2010-10-19 09:57:06

+0

读者可能会惊讶的发现,这实际上每一个位都像replicateM一样(非)神奇 - 事实上,这正是'replicateM n [0,1]'所做的。在[0,1]上抽象定义这个定义(即使用一个参数而不是硬编码),这个定义对列表monad来说就是_exactly_ replicateM。将[[]]更改为'return []'并将列表理解转换为具有完全相同操作的'do'块将会产生一个完美合适的replicateM定义。听起来像一个有益的Haskelist好运动:) – mokus 2010-10-19 14:31:03

+0

@mokus如果这两个功能没有做同样的事情,那么它会不会是正确的? = D,但实际上'replicateM n x'在Control.Monad中被定义为'sequence(replicate n x)',序列是使用foldr定义的。然而,解析listcomprehensions我们得到'f 0 = return []'和'f n = do {x < - [0,1]; xs < - f(n-1); return(x:xs)}''。所以replicateM使用一个列表来完成f中的递归。但是,当你说这样做时,完全适合制作复制品。 – HaskellElephant 2010-10-19 23:03:40

8

First of all pls refactore my code Haskell-way. I already know one magic refactring:

Control.Monad.replicateM n [0,1] 

but this solution is not good for studying purposes :)

其实,虽然我肯定不会指望一个新哈斯克尔拿出这样的解决方案,我认为理解这个版本将是研究的目的非常不错。

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

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

什么replicateM确实是按照元素的Monad“序列”列表中,把一些单子值[m a]列表为一元第二步值列表m [a]。它所做的就是在某种意义上“结合”每个一元值的结构,其中“结合”的具体含义取决于具体的monad。

作为Monad,列表代表类似尝试多种可能性。所以当我们对这些值进行“排序”时,这意味着在每一步中,每一种可能性都会被单独尝试,并且收集所有可能的结果。

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

> replicateM 2 ["0", "1"] 
[["0","0"],["0","1"],["1","0"],["1","1"]] 
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将是我的第一选择,但如果我想避免这将是我的解决方案。也许比列表理解解决方案不太清晰/简洁,但我觉得tail调用递归非常优雅。

相关问题