【问题标题】:Functor instance for generic polymorphic ADTs in Haskell?Haskell中通用多态ADT的函子实例?
【发布时间】: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。知道 ListFTreeF 这样的类型是 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,并且可以立即为上面的ListTree 类型工作(以及以类似方式定义的任何其他类型)。这可能吗?

如果是这样,是否有可能使其也与recursion-schemes 兼容?

【问题讨论】:

  • 这是您的法定提醒,因为“ADT”既代表“代数数据类型”又代表“抽象数据类型”,并且由于这两个概念激烈对立,因此“ADT”一词毫无意义最好避免。
  • @pigworker:从现在开始我们称它们为 uGADT 怎么样?

标签: haskell recursion functor category-theory


【解决方案1】:

bifunctors 包还提供了一个特别合适的Fix 版本:

newtype Fix p a = In {out :: p (Fix p a) a}

这很容易成为Functor 实例:

instance Bifunctor p => Functor (Fix p) where
  fmap f = In . bimap (fmap f) f . out

【讨论】:

    【解决方案2】:

    TBH 我不确定这个解决方案对你有多大帮助,因为它仍然需要额外的 newtype 包装这些定点函子,但我们开始吧:

    如果你做一些包装/解包,你可以继续使用你的通用 cata

    给定以下两个辅助函数:

    unwrapFixBifunctor :: (Bifunctor f) => Fix (WrappedBifunctor f a) -> Fix (f a)
    unwrapFixBifunctor = Fix . unwrapBifunctor . fmap unwrapFixBifunctor . unFix
    
    wrapFixBifunctor :: (Bifunctor f) => Fix (f a) -> Fix (WrappedBifunctor f a)
    wrapFixBifunctor = Fix . fmap wrapFixBifunctor . WrapBifunctor . unFix
    

    您可以定义gmap,而无需对f 施加任何额外限制:

    gmap :: (Bifunctor f) => (a -> b) -> Fix (f a) -> Fix (f b)
    gmap f = unwrapFixBifunctor . cata alg . wrapFixBifunctor
      where
        alg = inF . bimap f id
    

    您可以通过newtypeFix . f 变成Functor

    我们可以为\a -> Fix (f a) 实现一个Functor 实例,方法是将这个“类型级lambda”实现为newtype

    newtype FixF f a = FixF{ unFixF :: Fix (f a) }
    
    instance (Bifunctor f) => Functor (FixF f) where
        fmap f = FixF . gmap f . unFixF
    

    【讨论】:

    • bimap f id 应该写成Data.Bifunctor.first
    【解决方案3】:

    如果你在处理双函子的那一刻愿意接受,你可以说

    cata :: Bifunctor f => (f a r -> r) -> Fix (f a) -> r
    cata f = f . bimap id (cata f) . unFix
    

    然后

    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
    

    (在gmap 中,我刚刚重新安排了您的类约束以使作用域类型变量起作用。)

    您也可以使用原始版本的 cata,但是您需要同时使用 FunctorBifunctorgmap 的约束:

    gmap :: forall a b f. (Bifunctor f, Functor (f a)) => (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
    

    您不能将 gmap 设为普通 Functor 类的实例,因为它需要类似于

    instance ... => Functor (\ x -> Fix (f x))
    

    而且我们没有类型级别的 lambda。如果您反转f 的两个参数,您可以执行此操作,但是您会丢失“其他”Functor 实例并且需要再次为Bifunctor 定义cata。 p>

    [您可能也有兴趣阅读http://www.andres-loeh.de/IndexedFunctors/ 了解更通用的方法。]

    【讨论】:

    • 是否有可能以不同的方式解决问题,因此编写Functor 的实例确实成为可能?使用不同的类型,可能是类型类等?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-16
    • 2017-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-13
    相关资源
    最近更新 更多