haskell - 使用 wl-pprint 不可分组的换行符

标签 haskell pretty-print

我正在为一种简单的空白敏感语言编写一个 pretty-print 。

与 Wadler 库相比,我更喜欢 Leijen pretty-print 库,但是 Leijen 库在我的域中存在一个问题:我插入的任何换行符都可能被 group 构造覆盖,这可能会压缩任何行,这可能会改变输出的语义。

我认为我无法在 wl-pprint 中实现不可分组的行(尽管我很想错)。

稍微看一下 wl-pprint-extras 包,我认为即使是暴露的内部接口(interface)也不允许我创建一条不会被 group 压扁的线。

我是否必须依赖于我从不使用group的事实,或者我有更好的选择吗?

最佳答案

鉴于您希望能够进行分组,并且还需要能够确保某些行不会被取消插入, 为什么我们不利用库设计者在数据类型中编码语义的事实, 而不是在代码中。这个绝妙的决定使其具有出色的可重新设计性。

Doc 数据类型使用构造函数 Line::Bool -> Doc 对换行符进行编码。 Bool 表示删除一行时是否省略空格。 (行出现时会缩进。) 让我们替换 Bool:

data LineBehaviour = OmitSpace | AddSpace | Keep

data Doc = ...
    ...
    Line !LineBehaviour   -- not Bool any more

语义即数据设计的美妙之处在于,如果我们替换 此 Bool 数据与 LineBehaviour 数据,未使用它的函数,但 未更改地传递,不需要编辑。函数查看内部内容 Bool 因更改而中断 - 我们将准确重写代码的部分 需要通过更改数据类型来更改以支持新语义 旧的语义依然存在。在我们完成所有的操作之前,程序不会编译 我们应该进行更改,而我们不需要触及不这样做的代码行 取决于换行符语义。万岁!

例如,renderPretty 使用 Line 构造函数,但在模式 Line _ 中, 所以我们可以不管它。

首先,我们需要将 Line True 替换为 Line OmitSpace,将 Line False 替换为 Line AddSpace

line = Line AddSpace

linebreak = Line OmitSpace

但也许我们应该添加自己的

hardline :: Doc
hardline = Line Keep

我们也许可以使用使用它的二元运算符

infixr 5 <->
(<->) :: Doc -> Doc -> Doc
x <-> y = x <> hardline <> y

以及垂直分隔符的等效名称,我想不出比垂直分隔符更好的名称:

vvsep,vvcat :: [Doc] -> Doc
vvsep = fold (<->)
vvcat = fold (<->)

实际删除行发生在group函数中。一切都可以保持不变,除了:

flatten (Line break)    = if break then Empty else Text 1 " "

应改为

flatten (Line OmitSpace)    = Empty
flatten (Line AddSpace)     = Text 1 " "
flatten (Line Keep)         = Line Keep

就是这样:我找不到其他可以更改的内容!

关于haskell - 使用 wl-pprint 不可分组的换行符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12789845/

相关文章:

haskell - 使用带有镜头的一元函数修改状态

c++ - Eclipse/CDT pretty-print 错误

python - python 中紧凑但漂亮的 JSON 输出?

haskell - Haskell 中类型的余积(不相交并集)的语法是什么?

performance - 展开器与 zipWith 的效率

design-patterns - Haskell 演示了 OOP 设计模式的等效项

linux - cabal-install 安装失败

json - 可以在 Grails 1.3.7 中漂亮地打印 JSON 吗?

python - append 从文件读取的 xml 节点会破坏相邻节点的 Pretty_print

haskell - Haskell 中有 pretty-print (或显示)抽象吗?