(此响应使用数据修复库,因为我无法编译递归方案。)
我们可以将两棵树的差异建模为基于原始函子的“差异函子”的变形或展开。
考虑以下类型
data DiffF func r = Diff (Fix func) (Fix func)
| Nodiff (func r)
deriving (Functor)
type ExprDiff = Fix (DiffF ExprF)
这个想法是,只要它保持相等,ExprDiff它将遵循原始树的“公共结构” ,但是在遇到差异的那一刻,我们切换到叶子,它存储我们发现不同的两个子树。ExprDiff
实际的比较函数是:
diffExpr :: Expr -> Expr -> ExprDiff
diffExpr e1 e2 = ana comparison (e1,e2)
where
comparison :: (Expr,Expr) -> DiffF ExprF (Expr,Expr)
comparison (Fix (Const i),Fix (Const i')) | i == i' =
Nodiff (Const i')
comparison (Fix (Add a1 a2),Fix (Add a1' a2')) =
Nodiff (Add (a1,a1') (a2,a2'))
comparison (something, otherthing) =
Diff something otherthing
变形的“种子”是我们要比较的一对表达式。
如果我们只是想要一个谓词Expr -> Expr -> Bool,我们可以稍后使用检测分支存在的 catamorphism Diff。