異教徒の一般化である再帰スキームを「発明しました」。再帰スキームのライブラリ実装
{-# 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
の結果へのアクセスのみを持っている、ではなく、元のx
へ:あなたはcatamorphismとデータ構造を折るときにあなただけの折りたたみのsubresultsに、部分項にアクセスすることはできません。だから私は、参加機能を追加しました:
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では不可能な方法で 'サブターム'と 'サブサブルス'を組み合わせることができます。
私の質問はrecursion-schemes/Data.Functor.Foldable
のような最新の再帰スキームライブラリのストック機能を使用してprocessTerm
をビルドできますか?
cf. http://stackoverflow.com/questions/13317242/what-are-paramorphisms –