グループ化できるようにし、一部の行が挿入されていないことを確認する必要がある場合、ライブラリ設計者がコードではなくデータ型でセマンティクスをエンコードしたという事実を使用してみませんか。この素晴らしい決定により、非常に再設計可能になります。
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
それだけです:私は他に変更するものを見つけることができません!