是否可以将两棵树与递归方案进行比较?

ais*_*ais 11 tree haskell abstract-syntax-tree catamorphism recursion-schemes

我有这个AST

data ExprF r = Const Int | Add   r r
type Expr = Fix ExprF
Run Code Online (Sandbox Code Playgroud)

我想比较一下

x = Fix $ Add (Fix (Const 1)) (Fix (Const 1))
y = Fix $ Add (Fix (Const 1)) (Fix (Const 2))
Run Code Online (Sandbox Code Playgroud)

但是所有递归方案函数似乎只适用于单一结构

显然我可以使用递归

eq (Fix (Const x)) (Fix (Const y)) = x == y
eq (Fix (Add x1 y1)) (Fix (Add x2 y2)) = (eq x1 x2) && (eq y1 y2)
eq _ _ = False
Run Code Online (Sandbox Code Playgroud)

但我希望可以使用某种zipfold功能.

And*_*ács 5

作用于单个参数的递归方案就足够了,因为我们可以从方案应用程序中返回一个函数。在这种情况下,我们可以Expr -> Bool从上的方案应用返回函数Expr。为了进行有效的相等性检查,我们只需要同态:

{-# language DeriveFunctor, LambdaCase #-}

newtype Fix f = Fix (f (Fix f))
data ExprF r = Const Int | Add r r deriving (Functor, Show)
type Expr = Fix ExprF

cata :: Functor f => (f a -> a) -> Fix f -> a
cata f = go where go (Fix ff) = f (go <$> ff)

para :: Functor f => (f (Fix f, a) -> a) -> Fix f -> a
para f (Fix ff) = f ((\x -> (x, para f x)) <$> ff)

eqExpr :: Expr -> Expr -> Bool
eqExpr = cata $ \case
  Const i -> cata $ \case
    Const i' -> i == i'
    _        -> False
  Add a b -> para $ \case
    Add a' b' -> a (fst a') && b (fst b')
    _         -> False
Run Code Online (Sandbox Code Playgroud)

当然,cata在以下方面可以轻松实现para

cata' :: Functor f => (f a -> a) -> Fix f -> a
cata' f = para (\ffa -> f (snd <$> ffa)
Run Code Online (Sandbox Code Playgroud)

从技术上讲,几乎所有有用的功能都可以使用来实现cata,但不一定有效。我们可以para使用实现cata

para' :: Functor f => (f (Fix f, a) -> a) -> Fix f -> a
para' f = snd . cata (\ffa -> (Fix (fst <$> ffa) , f ffa))
Run Code Online (Sandbox Code Playgroud)

然而,如果我们使用para'eqExpr我们得到二次复杂,因为para'总是线性输入的大小,而我们可以用para在最上面的偷看Expr在固定的时间值。