Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell中泛型多态ADT的函子实例?_Haskell_Recursion_Functor_Category Theory - Fatal编程技术网

Haskell中泛型多态ADT的函子实例?

Haskell中泛型多态ADT的函子实例?,haskell,recursion,functor,category-theory,Haskell,Recursion,Functor,Category Theory,当谈到将范畴理论应用于泛型编程时,Haskell做得非常好,例如使用了递归方案之类的库。但是有一件事我不确定,那就是如何为多态类型创建泛型函子实例 如果您有多态类型,如列表或树,则可以创建一个从(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上是多态的,

当谈到将范畴理论应用于泛型编程时,Haskell做得非常好,例如使用了
递归方案
之类的库。但是有一件事我不确定,那就是如何为多态类型创建泛型函子实例

如果您有多态类型,如列表或树,则可以创建一个从(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
之类的类型都是双功能函数,到目前为止,我得到了以下结论:

{-# 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中,这给了我以下错误:
无法从上下文(Bifunctor f)推断使用cata时产生的(Functor(fa))

我使用的是
bifunctors
包,它有一个
WrappedBifunctor
类型,专门定义了以下实例,可以解决上述问题:
Bifunctor p=>Functor(WrappedBifunctor p a)
。但是,我不知道如何在
Fix
中“提升”这种类型才能使用它

2)即使可以定义上面的通用
gmap
,我也不知道是否有可能创建一个
Functor
的通用实例,该实例具有
fmap=gmap
,并且可以立即用于上面的
列表和
类型(以及以类似方式定义的任何其他类型). 这可能吗


如果是这样的话,有没有可能使它也与递归方案兼容呢?

如果你愿意在处理biFunctor时接受,你可以说

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
,但是您需要同时使用
Functor
gmap
上的
Bifunctor
约束:

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
的两个参数,那么您可以执行此操作,但随后您将丢失“other”
Functor
实例,并且需要再次为
Bifunctor
定义
cata
特定


[您可能也有兴趣阅读更一般的方法。]

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
你可以做
Fix。f
通过
newtype
通过将此“类型级别lambda”实现为
新类型,我们可以为
\a->Fix(fa)
实现一个
Functor
实例:

newtype FixF f a = FixF{ unFixF :: Fix (f a) }

instance (Bifunctor f) => Functor (FixF f) where
    fmap f = FixF . gmap f . unFixF

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

newtype Fix p a = In {out :: p (Fix p a) a}
这很容易成为一个
函子
实例:

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

这是您的法定提醒,因为“ADT”同时代表“代数数据类型”和“抽象数据类型”,而且这两个概念强烈对立,“ADT”一词毫无意义,最好避免使用。@pigworker:从现在起我们称之为UGADT怎么样?有可能以不同的方式处理这个问题吗,那么编写
函子的实例就成为可能了?使用不同的类型,可能是类型类等?
bimap f id
可能应该写入
Data.Bifunctor.first