我正在使用简单的模式匹配和monad遍历AST。Reader
在我的项目的其他地方,我定义了一个用于遍历 AST 的walk
函数,它的核心是用于将访问树中每个节点的结果减少为单个monoidalfoldl
结果(例如,从特殊的树中的节点)。
我的问题是:是否可以结合这两种方法并使用像我的函数这样的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
,可能在堆栈中)。
这些东西可以有效地结合起来吗?