问题描述
我有以下编程语言语法:
data Expr = ...
data Stmt = SExpr Expr | SBlock Block | SLet Fundef | ...
data Block = Block [Stmt]
data Fundef = Fundef String [String] Block
data TopDef = TopFun Fundef
使用以下示例语法:
function long_function_name () = {
let g() = {
{
h()
};
3
}
}
我正在尝试使用HughesPJ pretty
库为该语言创建漂亮的打印机。到目前为止,我的尝试如下:
instance Pretty Stmt where
pprint = \case
SExpr e -> pprint e
SBlock b -> pprint b
SLet f -> text "let" <+> pprint f
instance Pretty Block where
pprint (Block stmts) = lbrace $+$
nest 2 (vcat (punctuate semi (map pprint stmts))) $+$
rbrace
instance Pretty Fundef where
pprint (Fundef name args body) = pprint name <> parens (...) <+> text "=" <+> pprint body
instance Prettty TopDef where
pprint (TopFun f) = text "function" <+> pprint f
问题是,我想在函数声明的同一行中包含{
,但它总是使后面几行相对于括号列缩进,而不是绝对的。应该在上面的示例的漂亮字体中可见;
function long_function_name () = {
let g() = {
{
h()
};
3
}
}
为什么会发生这种情况,我该如何解决这个问题?我想尽可能避免重复代码。
解决方法
您在正文之前写了<+>
,因此$+$
的垂直串联完全在function
行的水平串联中,因此全部缩进了。我相信,pretty
的用途是在块上进行显式匹配,因为它是垂直布局的一部分,即:
pPrint (Fundef name args (Block stmts)) = vcat
[ pPrint name <> parens (...) <+> text "=" <+> lbrace,nest 2 (vcat (punctuate semi (map pPrint stmts))),rbrace
]
像prettyprinter
这样的更现代的漂亮打印库使此操作变得容易一些:nest
(或indent
或hang
)处理行缩进 跟随第一行以垂直布局排列,因此您可以将nest
放在左括号和主体之间,并将右括号放在嵌套外部,如下所示:
"prefix" <+> vcat
[ nest 4 $ vcat
[ "{","body"
],"}"
]
⇓
prefix {
body
}
(注意。您可以像这样使用OverloadedStrings
而不是将文字包装在text
中。)
但这不适用于pretty
,prettyprinter
似乎是为了使一切杂乱无章。
我还建议您使用group
的其他优点,例如,一个{{1}}函数可让您表达“如果合适,可将其放在一行上”,这对于使格式化稳固非常有用。并响应不同的渲染上下文。