我“发明”了一种递归方案,它是变态的推广。当您折叠具有多态性的数据结构时,您无法访问子项,只能访问折叠的子结果:
{-# LANGUAGE DeriveFunctor #-}
import qualified Data.Map as M
newtype Fix f = Fix { unFix :: f (Fix f) }
cata :: Functor f => (f b -> b) -> Fix f -> b
cata phi = self where
self = phi . fmap (\x -> self x) . unFix
折叠函数phi
只能访问 的结果self x
,而不能访问 original x
。所以我添加了一个加入功能:
cataWithSubterm :: Functor f => (Fix f -> c -> b) -> (f b -> c) -> Fix f -> c
cataWithSubterm join phi = self
where self = phi . fmap (\x -> join x (self x)) . unFix
现在可以以有意义的方式组合x
和self x
,例如使用(,)
:
data ExampleFunctor a = Var String | Application a a deriving Functor
type Subterm = Fix ExampleFunctor
type Result = M.Map String [Subterm]
varArgs :: ExampleFunctor (Subterm, Result) -> Result
varArgs a = case a of
Var _ -> M.empty
Application ((Fix (Var var)), _) (arg, m) -> M.insertWith (++) var [arg] m
processTerm :: (ExampleFunctor (Subterm, Result) -> Result) -> Subterm -> Result
processTerm phi term = cataWithSubterm (,) phi term
processTerm varArgs
为每个标识符返回它在不同控制路径上接收到的实际参数列表。例如,bar (foo 2) (foo 5)
它返回fromList [("foo", [2, 5])]
请注意,在此示例中,结果与其他结果统一组合,因此我希望存在使用Data.Foldable
. 但总的来说,情况并非如此,因为phi
可以应用其对内部结构的知识ExampleFunctor
来以 Foldable 无法实现的方式组合“子项”和“子结果”。
我的问题是:我可以processTerm
使用现代递归方案库中的库存函数进行构建recursion-schemes/Data.Functor.Foldable
吗?