使用变形来忘记 Cofree 注释
Forgetting Cofree annotations using a catamorphism
我有一个 AST,我正在使用 Cofree
:
进行注释
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:
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 = ???
任何帮助确定这是否真的是 cata/anamorphism,以及为什么它 is/isn 不是的一些直觉将不胜感激。
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
:
的类型开始
cata :: Recursive t => (Base t b -> b) -> t -> b
此处 t ~ Cofree f a
和 type 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
和更具体的 b
,即 Fix f
:
-- expected type of `cata` in `forget`
cata :: Functor f => ((a, f (Fix f)) -> Fix f) -> Cofree f a -> Fix f
forget
在a
和f
中是参数化的,所以我们给cata
的函数不能对a
做任何事情,并且实现剩余 f (Fix f) -> Fix f
的唯一明智方法是 Fix
包装器。
在操作上,Fix
是身份,所以 (\(_ :< z) -> Fix z)
实际上是 (\(_ :< z) -> z)
这对应于删除注释的直觉,即对的第一个组件 (_ :< z)
.
我有一个 AST,我正在使用 Cofree
:
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:
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 = ???
任何帮助确定这是否真的是 cata/anamorphism,以及为什么它 is/isn 不是的一些直觉将不胜感激。
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
:
cata :: Recursive t => (Base t b -> b) -> t -> b
此处 t ~ Cofree f a
和 type 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
和更具体的 b
,即 Fix f
:
-- expected type of `cata` in `forget`
cata :: Functor f => ((a, f (Fix f)) -> Fix f) -> Cofree f a -> Fix f
forget
在a
和f
中是参数化的,所以我们给cata
的函数不能对a
做任何事情,并且实现剩余 f (Fix f) -> Fix f
的唯一明智方法是 Fix
包装器。
在操作上,Fix
是身份,所以 (\(_ :< z) -> Fix z)
实际上是 (\(_ :< z) -> z)
这对应于删除注释的直觉,即对的第一个组件 (_ :< z)
.