単純なパターン マッチングとmonadを使用して ASTをトラバースしています。Reader
私のプロジェクトの他の場所で、AST をトラバースするためのwalk
関数foldl
を定義しました。これは、ツリー内の各ノードを訪問した結果を単一のモノイド結果に減らすために使用されます (たとえば、特別なオブジェクトから「シンボル テーブル」を生成するため)。ツリー内のノード)。
私の質問は、これら2つのアプローチを組み合わせて、私の関数のような関数を使用することは可能ですかwalk
?
walk :: Monoid a => (Node -> a) -> a -> Node -> a
walk f acc n = foldl (walk f) (acc <> f n) children
where
children = case n of
Blockquote b -> b
DocBlock d -> d
FunctionDeclaration {} -> functionBody n
List l -> l
ListItem i -> i
Paragraph p -> p
Unit u -> u
_ -> [] -- no Node children
そしてReader
— 以下のコードのトラバーサルのように (簡潔にするためにいくつかのビットは省略されています) — 同時に?
markdown :: Node -> String
markdown n = runReader (node n) state
where state = State (getSymbols n) (getPluginName n)
node :: Node -> Env
node n = case n of
Blockquote b -> blockquote b >>= appendNewline >>= appendNewline
DocBlock d -> nodes d
FunctionDeclaration {} -> nodes $ functionBody n
Paragraph p -> nodes p >>= appendNewline >>= appendNewline
Link l -> link l
List ls -> nodes ls >>= appendNewline
ListItem l -> fmap ("- " ++) (nodes l) >>= appendNewline
Unit u -> nodes u
ここでの使用の動機はwalk
、各パターンの子を取得する方法と AST の順序どおりのトラバーサルを実行する方法の知識が関数で既にエンコードされていることです。トラバーサルごとにそれを再実装したくないので、使用walk
する必要がある場所を含め、より多くの場所で使用するとよいでしょうReader
(後でState
、おそらくスタック内で)。
これらをうまく組み合わせることができるでしょうか。