【发布时间】:2016-12-30 13:50:14
【问题描述】:
我有这种语言 AST
data ExprF r = Const Int
| Var String
| Lambda String r
| EList [r]
| Apply r r
deriving ( Show, Eq, Ord, Functor, Foldable )
我想把它转换成字符串
toString = cata $ \case
Const x -> show x
Var x -> x
EList x -> unwords x
Lambda x y -> unwords [x, "=>", y]
Apply x y -> unwords [x, "(", y, ")"]
但是当 Apply 中使用 lambda 时,我需要括号
(x => x)(1)
但我无法将内部结构与 cata 匹配
toString :: Fix ExprF -> String
toString = cata $ \case
Const x -> show x
Var x -> x
Lambda x y -> unwords [x, "=>", y]
Apply (Lambda{}) y -> unwords ["(", x, ")", "(", y, ")"]
Apply x y -> unwords [x, "(", y, ")"]
还有比para更好的解决方案吗?
toString2 :: Fix ExprF -> String
toString2 = para $ \case
Const x -> show x
Var x -> x
Lambda x (_,y) -> unwords [x, "=>", y]
EList x -> unwords (snd <$> x)
Apply ((Fix Lambda {}),x) (_,y) -> unwords ["(", x, ")", "(", y, ")"]
Apply (_,x) (_,y) -> unwords [x, "(", y, ")"]
看起来更丑。即使只在一个地方需要它,我也需要在所有地方删除 fst 元组参数,我想它会更慢。
【问题讨论】:
-
在一般情况下,您可以采用
showsPrec中的优先级参数。不过,帕拉对我来说并不算太糟糕。 -
您能详细说明一下吗?我看不出我可以把这个论点放在哪里。在这种情况下,
para是可以的,但是当 ast 更大时,噪音太大了 -
您可以使用 cata 构建一个函数:类似
cata $ \case Var x -> const x ; Apply x y -> \_ -> unwords [x 5, y 5] ; Lambda x y -> (\p -> if p==5 then addParen (x 0) (y 0) else noParen (x 0) (y 0) ; ...根据需要调整优先级数,并在顶层传递一个初始 0,以便结果是一个字符串。 -
@ais 您可能喜欢this question on pretty-printing boolean formulae 中的讨论,了解更多关于
showsPrec方法的信息。 -
@ais Bool 如果您只有两个优先级,则很好。在一般情况下,您需要更多。上面 Daniel Wagner 的链接就是这样一个例子。
标签: haskell recursion abstract-syntax-tree catamorphism recursion-schemes