【问题标题】:How does one pretty print recursion depth in Haskell?在 Haskell 中如何打印一个漂亮的递归深度?
【发布时间】:2013-02-26 01:52:03
【问题描述】:

假设我有一棵二叉树。

main = putStrLn $ printTree tree                                                                                                                                                                                

data Tree = Empty | Node Int (Tree) (Tree) deriving (Show)                                                                                                                                                      

tree = Node 4 (Node 3 Empty (Node 2 Empty Empty)) Empty                                                                                                                                                         

printTree :: Tree -> String                                                                                                                                                                                     
printTree x = case x of                                                                                                                                                                                         
  Node num treeA treeB -> show num ++ "\n" ++ printTree treeA ++ "\n" ++ printTree treeB                                                                                                                        
  Empty -> "Empty" 

输出

*Main> main                                                                                                                                                                                                     
4                                                                                                                                                                                                               
3                                                                                                                                                                                                               
Empty                                                                                                                                                                                                           
2                                                                                                                                                                                                               
Empty                                                                                                                                                                                                           
Empty                                                                                                                                                                                                           
Empty 

所需的输出(用制表符或双空格分隔即可)

*Main> main                                                                                                                                                                                                     
    4                                                                                                                                                                                                               
      3                                                                                                                                                                                                               
        Empty                                                                                                                                                                                                           
        2                                                                                                                                                                                                               
          Empty                                                                                                                                                                                                           
          Empty                                                                                                                                                                                                           
      Empty 

【问题讨论】:

  • 首先返回[String],而不是String。将输出设置为行列表允许您轻松修改递归调用产生的每一行。

标签: haskell pretty-print


【解决方案1】:

您可以使用累加器(此处为depth)来跟踪您当前在树中的深度 - 然后创建与线所在深度相对应的多个空格:

main = putStrLn $ printTree tree
data Tree = Empty | Node Int (Tree) (Tree) deriving (Show)
tree = Node 4 (Node 3 Empty (Node 2 Empty Empty)) Empty

printTree :: Tree -> String
printTree x = printTree' x 0 
  where 
    printTree' x depth = case x of
      Node num treeA treeB -> (replicate (2 * depth) ' ') ++ show num ++ "\n" ++ (printTree' treeA (depth + 1)) ++ "\n" ++ (printTree' treeB (depth + 1))
      Empty -> (replicate (2 * depth) ' ') ++ "Empty" 

输出:

*Main> main
4
  3
    Empty
    2
      Empty
      Empty
  Empty

【讨论】:

    【解决方案2】:

    这是在 GHC 中使用 -XImplicitParams 的解决方案

    {-# LANGUAGE ImplicitParams #-}
    module ImplicitTabs where
    
    data Tree = Empty | Node Int (Tree) (Tree) deriving (Show)
    tree = Node 4 (Node 3 Empty (Node 2 Empty Empty)) Empty                                         
    
    tab :: (?tab_level :: Int) => String
    tab = replicate (2 * ?tab_level) ' '
    
    printTree :: (?tab_level :: Int) => Tree -> String
    printTree x = let 
        ?tab_level = ?tab_level + 1
      in case x of
        Node num treeA treeB -> tab ++ show num ++ "\n" ++ tab ++ printTree treeA ++ "\n" ++ tab ++ printTree treeB
        Empty -> tab ++ "Empty" 
    
    main = let ?tab_level = -1 in putStrLn $ printTree tree
    
    
    > runhaskell implicit-tabulation.hs 
    4
      3
          Empty
          2
              Empty
              Empty
      Empty
    

    【讨论】:

    • IMO ImplicitParams 在这里完全是矫枉过正。一个常规参数会很好......
    【解决方案3】:

    好的,我想我已经成功了。

    printTree :: Tree -> String                                                                                                                                                                                     
    printTree x = printT 0 x                                                                                                                                                                                                                   
    
    space x = take x $ cycle " "                                                                                                                                                                                    
    
    printT :: Int -> Tree -> String                                                                                                                                                                                 
    printT num x =                                                                                                                                                                                                  
      case x of                                                                                                                                                                                                     
        (Node o treeA treeB) -> show o ++                                                                                                                                                                           
                              "\n" ++                                                                                                                                                                               
                              space num ++                                                                                                                                                                          
                              printT (num+1) treeA ++                                                                                                                                                               
                              "\n" ++                                                                                                                                                                               
                              space num ++                                                                                                                                                                          
                              printT (num+1) treeB                                                                                                                                                                  
        Empty -> "Empty"  
    

    【讨论】:

      【解决方案4】:

      如果您转换为Data.Tree,那么您可以使用库函数drawTree,它几乎可以满足您的需求(它还使用ASCII 艺术绘制分支)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-07-07
        • 2019-09-08
        • 2012-05-04
        • 2014-06-28
        • 1970-01-01
        • 2011-01-02
        • 2014-05-10
        • 1970-01-01
        相关资源
        最近更新 更多