【问题标题】:Pretty printing expression structure in Haskell?Haskell中漂亮的打印表达式结构?
【发布时间】:2014-05-10 06:14:03
【问题描述】:

我们的作业得到以下数据结构:

-- Question 2: Expression tree.
data Expr
  = Lit Float
  | Add Expr Expr
  | Sub Expr Expr
  | Mul Expr Expr
  | Div Expr Expr
  | X

它代表一个浮点值,两个子树的add/sub/mul/div,或者一个代表未知变量的X。我们必须编写一个可以漂亮地打印树的方法。这是我目前所拥有的:

draw :: Expr -> Int -> String
draw (Lit f) _ = show f
draw (X) _ = "X"
draw (Add a b) lvl = indent lvl ++ "(+) ---" ++ draw a (lvl+1) ++ "\n" ++ indent lvl ++ "|\n" ++ indent lvl ++ "---" ++ draw b (lvl+1) 
draw (Sub a b) lvl = indent lvl ++ "(-) ---" ++ draw a (lvl+1) ++ "\n" ++ indent lvl ++ "|\n" ++ indent lvl ++ "---" ++ draw b (lvl+1) 
draw (Mul a b) lvl = indent lvl ++ "(*) ---" ++ draw a (lvl+1) ++ "\n" ++ indent lvl ++ "|\n" ++ indent lvl ++ "---" ++ draw b (lvl+1) 
draw (Div a b) lvl = indent lvl ++ "(/) ---" ++ draw a (lvl+1) ++ "\n" ++ indent lvl ++ "|\n" ++ indent lvl ++ "---" ++ draw b (lvl+1) 

indent :: Int -> [Char]
indent 0 = []
indent n = "\t"++indent (n-1)

这适用于简单的树:

myE2 :: Expr
myE2 = Add (Lit 4) (Sub (Lit 4) (Lit 2))

打印为:

*Main> putStr(draw myE2 0)
(+) ---4.0
|
--- (-) ---4.0
     |
     ---2.0

这是我想要的,但是,更复杂的树,例如:

myExpr :: Expr
myExpr = (Add (Add (Sub (Mul (Lit 4) (X)) (Lit 1)) (Lit 4)) (Lit 6))

打印为:

*Main> putStr(draw myExpr 0)
(+) --- (+) ---     (-) ---         (*) ---4.0
            |
            ---X
        |
        ---1.0
    |
    ---4.0
|
---6.0

谁能就我如何解决这个问题提供建议?

【问题讨论】:

  • 一个简单的选择:使用其unfoldTree 函数将您的Expr 转换为标准Data.Tree,然后调用drawTree 函数。
  • 这是家庭作业;我们不允许使用它。
  • 如果它不需要以这种格式进行漂亮打印,您可能会喜欢a previous similar question 对漂亮打印表单的最小括号。

标签: haskell tree pretty-print


【解决方案1】:

首先,您必须使用您当前使用的表达式格式样式吗?这种格式需要将许多节点打印到一行。如果您查看Data.Tree.Pretty 使用的格式,它只会将单个节点打印到任何行。如果您以这种方式格式化您的代码,myExpr 将具有如下格式:

(+)
 |
 +-(+)
 |  |
 |  +-(-)
 |  |  |
 |  |  +-(*)
 |  |  |  |
 |  |  |  +-4
 |  |  |  |
 |  |  |  +-X
 |  |  |
 |  |  +-1
 |  |
 |  +-4
 |
 +-6

这让问题变得更加简单,非常,因为每个节点都有一行。打印出一个节点所需要做的就是知道它在树中的深度。例如,深度为 3 的节点将有一行以" | | +-" 开头。然后从左到右打印每个节点,你就会得到结果。如果您遇到困难,请尝试查看source for the Data.Tree.drawTree 以获得一些灵感。

如果您必须坚持当前的格式,请准备好进行大量工作。您必须根据每个节点中文本的宽度动态布局树。您还需要分散节点,以免重叠。在开始之前,您需要考虑整棵树。这是一个 NP 完全问题。有关更多详细信息,请参阅this tree article。不过,这肯定超出了家庭作业的范围......

【讨论】:

  • 我认为每个节点中文本的宽度并不重要,因为唯一的可变宽度节点 Lit 是叶节点。
【解决方案2】:

您可以尝试以下方法:

data Expr
  = Lit Float
  | Add Expr Expr
  | Sub Expr Expr
  | Mul Expr Expr
  | Div Expr Expr
  | X

draw :: Expr -> Int -> String
draw (Lit f) _ = show f
draw (X) _ = "X"
draw (Add a b) lvl = "(+) ---" ++ draw a (lvl+1) ++ "\n" ++ indent lvl ++ " |\n" ++ indent lvl ++ " ------" ++ draw b (lvl+1) 
draw (Sub a b) lvl = "(-) ---" ++ draw a (lvl+1) ++ "\n" ++ indent lvl ++ " |\n" ++ indent lvl ++ " ------" ++ draw b (lvl+1) 
draw (Mul a b) lvl = "(*) ---" ++ draw a (lvl+1) ++ "\n" ++ indent lvl ++ " |\n" ++ indent lvl ++ " ------" ++ draw b (lvl+1) 
draw (Div a b) lvl = "(/) ---" ++ draw a (lvl+1) ++ "\n" ++ indent lvl ++ " |\n" ++ indent lvl ++ " ------" ++ draw b (lvl+1) 

indent :: Int -> [Char]
indent 0 = []
indent n = "       " ++ indent (n-1)

myE2 = Add (Lit 4) (Sub (Lit 4) (Lit 2))
myE3 = Add (Add (Lit 4) (Lit 3)) (Sub (Lit 4) (Lit 2))
myE4 = Add (Add (Lit 4) (Add (Lit 4) (Sub (Lit 4) (Lit 2)))) (Sub (Lit 4) (Lit 2))
myExpr = (Add (Add (Sub (Mul (Lit 4) (X)) (Lit 1)) (Lit 4)) (Lit 6))

它适用于我使用的不同条件。主要变化: 1.我把“\t”改成了spcaes。 2.我删除了第一个缩进。

[ghci] putStrLn $ draw myExpr 0
(+) ---(+) ---(-) ---(*) ---4.0
                      |
                      ------X
               |
               ------1.0
        |
        ------4.0
 |
 ------6.0

[ghci] putStrLn $ draw myE4 0
(+) ---(+) ---4.0
        |
        ------(+) ---4.0
               |
               ------(-) ---4.0
                      |
                      ------2.0
 |
 ------(-) ---4.0
        |
        ------2.0

[ghci] putStrLn $ draw myE3 0
(+) ---(+) ---4.0
        |
        ------3.0
 |
 ------(-) ---4.0
        |
        ------2.0

【讨论】:

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