使用同形异象方式忘记Cofree注释

时间:2018-06-26 18:23:56

标签: haskell functional-programming category-theory recursion-schemes catamorphism

我有一个使用Cofree进行注释的AST:

data ExprF a
  = Const Int
  | Add a
        a
  | Mul a
        a
  deriving (Show, Eq, Functor)

我用type Expr = Fix ExprF代表未标记的AST,type AnnExpr a = Cofree ExprF a代表标记的AST。我想出了一个通过丢弃所有注释将带标签的AST转换为无标签的AST的功能:

forget :: Functor f => Cofree f a -> Fix f
forget = Fix . fmap uncofree . unwrap

这看起来可能是某种形式的变形(我使用的是Kmett的recursion-schemes包中的定义)。

cata :: (Base t a -> a) -> t -> a
cata f = c where c = f . fmap c . project

我认为以上使用同构方法重写的内容看起来像这样,但是我不知道要为alg进行类型检查而放什么。

forget :: Functor f => Cofree f a -> Fix f
forget = cata alg where
  alg = ???

任何帮助弄清楚这是否真的是催化剂/变形,对于为什么/不是这种原因的一些直觉将不胜感激。

1 个答案:

答案 0 :(得分:5)

forget :: Functor f => Cofree f a -> Fix f
forget = cata (\(_ :< z) -> Fix z)
-- (Control.Comonad.Trans.Cofree.:<)
-- not to be confused with
-- (Control.Comonad.Cofree.:<)

说明

仅查看类型,我们可以证明实际上只有一种方法可以实现forget

cata :: Recursive t => (Base t b -> b) -> t -> b

t ~ Cofree f atype instance of Base for Cofree给出:

type instance Base (Cofree f a) = CofreeF f a

CofreeF在哪里:

data CoFreeF f a b = a :< f b
-- N.B.: CoFree also defines a (:<) constructor so you have to be
-- careful with imports.

,即花式对类型。让我们将其替换为实际的对类型,以使事情更清楚:

cata :: Functor f => ((a, f b) -> b) -> Cofree f a -> b

现在,我们实际上是在以更具体的cata(即a)为特色Fix f

-- expected type of `cata` in `forget`
cata :: Functor f => ((a, f (Fix f)) -> Fix f) -> Cofree f a -> Fix f

forgetaf中是参数化的,因此我们给cata赋予的功能对于成对的a无效,并且唯一f (Fix f) -> Fix f包装器是实现其余Fix的明智方式。

操作上,Fix是标识,所以(\(_ :< z) -> Fix z)实际上是(\(_ :< z) -> z),它对应于删除注释的直觉,即(_ :< z)对中的第一个组件