【问题标题】:How to solve correctly pascal triangle in haskell?如何在haskell中正确解决帕斯卡三角形?
【发布时间】:2020-08-11 05:15:49
【问题描述】:

我正在 Haskell 中实现 Pascal Triangle,但代码运行不正确。该代码又给出了 1 行。我也尝试像树一样打印结果,但这对我来说既困难又困惑,所以我没有添加打印代码。

这些是我得到的结果:

*Main> pascal 1
[[1],[1,1]]
*Main> pascal 2
[[1],[1,1],[1,2,1]]

预期输出:

*Main> pascal 2
    [[1],[1,1]]

理想输出:

*Main> pascal 3
           
         1  
        1 1 
       1 2 1

这是代码:

choose n 0 = 1
choose 0 k = 0
choose n k = choose (n-1) (k-1)* n `div` k

pascal :: Integer -> [[Integer]]
pascal 0 = [[1]]
pascal m = pascal (m - 1) ++ [[choose m k | k <- [0,1..m]]]

【问题讨论】:

  • 那么...您对pascal 1 的预期输出是[[1]] 吗?如果是这样,这不只是有错误的基本情况吗?
  • @Carl 测试简单地修复基本情况是否会产生与给定预期输出相匹配的函数是一件容易的事情。你试过那个测试吗?
  • 我问了一个关于在haskell中记忆pascals triangle的问题,也许会给一些启发stackoverflow.com/questions/11473130/…
  • 编辑不得使现有答案无效。我将它回滚到第一个版本,对标题进行了小幅编辑。
  • 我猜,帖子就这样了。我向question on Meta 询问了关于编辑大战的问题,受此启发。如果 OP 想要,我将删除此 SO 帖子的链接。

标签: haskell recursion pascals-triangle


【解决方案1】:

首先让我注意到你的方法有点倒退。帕斯卡三角形的全部要点在于它提供了一种有效的方法来将choose 函数 单独计算每个值。这并不意味着你的做法是错误,但它肯定不是很好。请尝试在没有choose 功能的情况下解决问题!你知道的,

                 1
                ╱ ╲
               1   1
              ╱ ╲+╱ ╲
             1   2   1
            ╱ ╲+╱ ╲+╱ ╲
           1   3   3   1
          ╱ ╲+╱ ╲+╱ ╲+╱ ╲
         1   4   6   4   1
        ...     ...     ...

提示:不要从编写一个计算整个三角形或单个元素的函数开始,而是先编写一个计算三角形的一个 并为您提供下一行的函数。那么剩下要做的就是iterateing 那个函数。

至于如何在您当前的方法中修复它 - 好吧,显然如果您希望 pascal 1 产生 [[1]] 那么 pascal 0 = [[1]] 不能是一个非常明智的基本情况。相反,开始

pascal 1 = [[1]]

pascal 0 = []

(这要好一些,因为该函数不会为零定义......但仍然适用于负数——我们希望避免这种情况,或者至少在这种情况下给出明确的错误消息。)

然后,对于mth 行,您应该只计算choose (m-1) k 系列。易于修复。请记住还要为k 选择正确的范围。

关于如何将输出打印成漂亮的等腰形状:编写一个辅助函数

centerAlign :: [String] -> [String]

在每行前面添加空格,对应于 lengthmaximum-length 相比缺少的一半。

然后你可以简单地在帕斯卡三角形上做putStrLn . unlines . centerAlign . map show

【讨论】:

    【解决方案2】:

    这是获得“理想输出”的代码:

    printPascal :: [[Integer]] -> IO ()
    printPascal pasc = 
      let                      
         process row = 
          let 
           striped = (foldr1 (\ x y -> x ++ " " ++ y) . map show) row
           spaces = replicate ((n - length striped) `div` 2) ' '
          in spaces ++ striped ++ "\n"
                       
         n = length . (foldr1 (\ x y -> x ++ " " ++ y) . map show) . last $ pasc
      in mapM_ (putStr . process) pasc
    

    首先,这里有一些示例(后一个看起来不太好,说实话 - 请参阅编辑以获得更好的版本):

    GHCi> printPascal (pascal 1)
    1
    GHCi> printPascal (pascal 4)
       1   
      1 1  
     1 2 1 
    1 3 3 1  
    GHCi> printPascal (pascal 8)
             1         
            1 1        
           1 2 1       
          1 3 3 1      
         1 4 6 4 1     
       1 5 10 10 5 1   
     1 6 15 20 15 6 1 
    1 7 21 35 35 21 7 1
    

    那么,这里发生了什么:

    1. 我们采用已构建的三角形pasc。我们将最后一行变成一个字符串,将所有元素放在一个字符串中,用空格分隔。这就是我们最后一个三角形中每一行的长度。
    2. 我们获取每一行并使用process 处理它。它做了一件简单的事情:它将所有元素放在一个字符串中,用空格分隔。如果它的长度小于n,它会添加缺失的空格(左右两边的数量相等;事实上,右边的空格可能会被删除,因为它已经完成了)。最后我们换了一行。
    3. 我们将putStr . process 映射到列表上,然后对效果进行排序。 mapM(或其更通用的版本 - traverse)用于此类目的。生成的类型将是 IO [()] - 我们不需要单位列表,因此我们通过将 mapM 替换为 mapM_(或其更通用的版本 - traverse_)使其成为 IO ()

    您可能希望将pascalprintPascal 结合起来:

    buildAndPrintPascal :: Integer -> IO ()
    buildAndPrintPascal = printPascal . pascal
    

    编辑:为了让树对于更大的数字看起来更好一些,我们可能想要更改步长(保持奇数)。这是代码的编辑版本,唯一的编辑是step

    printPascal :: [[Integer]] -> IO ()
    printPascal pasc = 
      let                      
         process row = 
          let 
           striped = (foldr1 (\ x y -> x ++ step ++ y) . map show) row
           spaces = replicate ((n - length striped) `div` 2) ' '
          in spaces ++ striped ++ "\n"
                       
         n = length . (foldr1 (\ x y -> x ++ step ++ y) . map show) . last $ pasc
         step = 
           let 
            times = (floor . logBase 10 . fromInteger . maximum . last $ pasc) * 2 + 1
           in replicate times ' '
      in mapM_ (putStr . process) pasc
    

    以下是一些示例:

    GHCi> buildAndPrintPascal 4
       1   
      1 1  
     1 2 1 
    1 3 3 1
    GHCi> buildAndPrintPascal 8
                    1                
                  1   1              
                1   2   1            
              1   3   3   1          
            1   4   6   4   1        
         1   5   10   10   5   1     
      1   6   15   20   15   6   1  
    1   7   21   35   35   21   7   1
    GHCi> buildAndPrintPascal 10
                                   1                               
                                1     1                            
                             1     2     1                         
                          1     3     3     1                      
                       1     4     6     4     1                   
                   1     5     10     10     5     1               
               1     6     15     20     15     6     1           
            1     7     21     35     35     21     7     1        
        1     8     28     56     70     56     28     8     1    
    1     9     36     84     126     126     84     36     9     1
    

    我认为它们看起来更好一些。

    【讨论】:

      猜你喜欢
      • 2015-01-29
      • 1970-01-01
      • 2012-10-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-19
      • 1970-01-01
      • 2014-11-12
      相关资源
      最近更新 更多