递归方案的观点是将递归类型视为函子的固定点。表达式的类型是以下函子的不动点:
data ExprF expr = Const Int
| Add expr expr
更改变量名称的目的是明确表明它是实际表达式类型的占位符,否则将定义为:
data Expr = Const Int | Add Expr Expr
在Stmt
中,有两种递归类型,Expr
和Stmt
它本身。所以我们放了两个洞/未知数。
data StmtF expr stmt = Compound [stmt]
| Print expr
Fix
当我们用or取一个固定点时Cofree
,我们现在正在求解一个由两个方程组成的系统(一个代表Expr
,一个代表Stmt
),并且带有一些样板。
我们没有直接应用Fix
or Cofree
,而是将这些固定点组合子 ( Fix
, Cofree
, Free
) 作为构造表达式和语句的参数进行概括:
type Expr_ f = f ExprF
type Stmt_ f = f (StmtF (Expr_ f))
现在我们可以说Expr_ Fix
或Stmt_ Fix
对于未注释的树,and Expr_ (Flip Cofree ann)
,Stmt_ (Flip Cofree ann)
。不幸的是,我们必须支付另一笔 LOC 费用才能使类型匹配,并且类型变得更加复杂。
newtype Flip cofree a f b = Flip (cofree f a b)
(这也假设我们想在同一时间使用相同的Fix
或Cofree
无处不在的。)
要考虑的另一种表示是(现在称为 HKD):
data Expr f = Const Int
| Add (f Expr) (f Expr)
data Stmt f = Compount [f Stmt]
| Print (f (Expr f))
您只能从注释/无注释(f = Identity
或(,) ann
)中抽象,而不是从递归中抽象。