我想在Haskell中打印一个抽象语法树。目前我可以逐行打印树,但我更喜欢的是为解析后的代码所在的每个块缩进它。
E.g。
要解析的代码:
module test
foo(x,y):
foo x y
x + y
以下是我创建和打印AST的功能。
返回树。
parse :: String -> Either ParseError [Expr]
parse = runParser (many expr <* eof) () "[input]" . indentConfig
打印树。
printTree :: String -> IO ()
printTree line = do
let res = parse line
case res of
Left err -> print err
Right ex -> mapM_ print ex
当前输出:
Function "foo" ["x","y"] (FunctionCall "foo" [Variable "x",Variable "y"])
BinOp Plus (FunctionCall "x" []) (FunctionCall "y" [])
期望的输出:
Function "foo" ["x","y"]
(FunctionCall "foo" [Variable "x",Variable "y"])
BinOp Plus (FunctionCall "x" []) (FunctionCall "y" [])
实现这一目标的最佳方法是什么?
答案 0 :(得分:2)
Hackage上有几个软件包可以让你以“缩进”的方式显示这样的树结构。以前,我使用了Iavor Diatchki的pretty-show
包,它做得非常好。您可能想尝试一下:https://hackage.haskell.org/package/pretty-show
答案 1 :(得分:1)
您可以创建自己的prettyPrint
函数,该函数接收AST和缩进级别,然后以递归方式打印AST中的节点,根据需要递增缩进级别。
在此函数中,您需要专门处理增加缩进级别的AST节点。
这是一个这样的功能的例子。
data AST =
Function String [String] [AST]
| BinOp AST AST AST
| Plus
| FunctionCall String [AST]
| Variable String
deriving (Show)
prettyPrint :: Int -> AST -> String
prettyPrint n (Function a b c) = "Function " ++ show a ++ " " ++ show b ++
foldl (++) "" (map (\x -> "\n" ++ take (n + 1) (repeat '\t') ++
prettyPrint (n + 1) x) c)
prettyPrint n a = show a
请注意,编写此函数的方法可能更为简洁,但此版本显示了该功能。
如果我们在你给出的示例AST上运行它,我们得到以下结果。
λ ~ let a = (Function "foo" ["x","y"] [FunctionCall "foo" [Variable "x",Variable "y"], BinOp Plus (FunctionCall "x" []) (FunctionCall "y" [])])
λ ~ putStrLn (prettyPrint 0 a)
Function "foo" ["x","y"]
FunctionCall "foo" [Variable "x",Variable "y"]
BinOp Plus (FunctionCall "x" []) (FunctionCall "y" [])
这也适用于多级缩进。
λ ~ let b = (Function "foo" ["x","y"] [FunctionCall "foo" [Variable "x",Variable "y"], BinOp Plus (FunctionCall "x" []) (FunctionCall "y" []), Function "bar" ["x"] [BinOp Plus (FunctionCall "x" []) (FunctionCall "y" [])]])
b :: AST
λ ~ putStrLn (prettyPrint 0 b)
Function "foo" ["x","y"]
FunctionCall "foo" [Variable "x",Variable "y"]
BinOp Plus (FunctionCall "x" []) (FunctionCall "y" [])
Function "bar" ["x"]
BinOp Plus (FunctionCall "x" []) (FunctionCall "y" [])
请注意,仅当您想要自己实现此功能时才会这样做。从长远来看,使用漂亮的打印库来处理这个问题可能是一个更好的举措。