【发布时间】:2015-03-07 13:29:35
【问题描述】:
在将范畴理论应用于泛型编程时,Haskell 做得非常好,例如使用像 recursion-schemes 这样的库。然而,我不确定的一件事是如何为多态类型创建通用仿函数实例。
如果你有一个多态类型,比如 List 或 Tree,你可以创建一个从 (Hask × Hask) 到 Hask 的仿函数来代表它们。例如:
data ListF a b = NilF | ConsF a b -- L(A,B) = 1+A×B
data TreeF a b = EmptyF | NodeF a b b -- T(A,B) = 1+A×B×B
这些类型在 A 上是多态的,但在 B 上是固定点,如下所示:
newtype Fix f = Fix { unFix :: f (Fix f) }
type List a = Fix (ListF a)
type Tree a = Fix (TreeF a)
但正如大多数人所知,列表和树也是通常意义上的函子,它们代表a 的“容器”,您可以映射函数f :: a -> b 以获取b 的容器的。
我试图弄清楚是否有办法以通用方式使这些类型(固定点)成为Functor 的实例,但我不确定如何。到目前为止,我遇到了以下两个问题:
1) 首先,必须有一种方法可以在任何多态不动点上定义泛型gmap。知道 ListF 和 TreeF 这样的类型是 Bifunctors,到目前为止我已经得到了这个:
{-# LANGUAGE ScopedTypeVariables #-}
import Data.Bifunctor
newtype Fix f = Fix { unFix :: f (Fix f) }
cata :: Functor f => (f a -> a) -> Fix f -> a
cata f = f . fmap (cata f) . unFix
-- To explicitly use inF as the initial algebra
inF :: f (Fix f) -> Fix f
inF = Fix
gmap :: forall a b f. Bifunctor f => (a -> b) -> Fix (f a) -> Fix (f b)
gmap f = cata alg
where
alg :: f a (Fix (f b)) -> Fix (f b)
alg = inF . bimap f id
在 Haskell 中,这给了我以下错误:Could not deduce (Functor (f a)) arising from a use of cata from the context (Bifunctor f)。
我正在使用bifunctors 包,它有一个WrappedBifunctor 类型,专门定义了以下可以解决上述问题的实例:Bifunctor p => Functor (WrappedBifunctor p a)。但是,我不确定如何在 Fix 中“提升”这种类型以便能够使用它
2) 就算上面的泛型gmap可以定义,不知道能不能创建一个泛型的Functor的实例有fmap = gmap,并且可以立即为上面的List 和Tree 类型工作(以及以类似方式定义的任何其他类型)。这可能吗?
如果是这样,是否有可能使其也与recursion-schemes 兼容?
【问题讨论】:
-
这是您的法定提醒,因为“ADT”既代表“代数数据类型”又代表“抽象数据类型”,并且由于这两个概念激烈对立,因此“ADT”一词毫无意义最好避免。
-
@pigworker:从现在开始我们称它们为 uGADT 怎么样?
标签: haskell recursion functor category-theory