如何使用 HughesPJ 的漂亮打印库正确缩进块?
How to properly indent blocks using HughesPJ's pretty printing library?
我有以下编程语言语法:
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
]
更现代的 pretty-printing 库,如 prettyprinter
使这更容易一些:nest
(或 indent
,或 hang
)处理缩进在垂直布局中第一行 之后 行,因此您可以将 nest
放在左大括号和正文周围,以及嵌套外的右大括号,如下所示:
"prefix" <+> vcat
[ nest 4 $ vcat
[ "{"
, "body"
]
, "}"
]
⇓
prefix {
body
}
(注意。您可以像这样使用 OverloadedStrings
而不是将文字包装在 text
中。)
但这不适用于 pretty
,它似乎旨在让一切都保持一致。
我还推荐prettyprinter
,因为它的其他优点,例如group
一个函数,可以表达“如果合适就放在一行”,这对制作非常有帮助格式稳健且响应不同的渲染上下文。
我有以下编程语言语法:
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
]
更现代的 pretty-printing 库,如 prettyprinter
使这更容易一些:nest
(或 indent
,或 hang
)处理缩进在垂直布局中第一行 之后 行,因此您可以将 nest
放在左大括号和正文周围,以及嵌套外的右大括号,如下所示:
"prefix" <+> vcat
[ nest 4 $ vcat
[ "{"
, "body"
]
, "}"
]
⇓
prefix {
body
}
(注意。您可以像这样使用 OverloadedStrings
而不是将文字包装在 text
中。)
但这不适用于 pretty
,它似乎旨在让一切都保持一致。
我还推荐prettyprinter
,因为它的其他优点,例如group
一个函数,可以表达“如果合适就放在一行”,这对制作非常有帮助格式稳健且响应不同的渲染上下文。