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函子实例 问题:_Haskell_Recursion_Functor_Algebraic Data Types_Category Theory - Fatal编程技术网

使用递归方案的泛型多态代数数据类型的Haskell函子实例 问题:

使用递归方案的泛型多态代数数据类型的Haskell函子实例 问题:,haskell,recursion,functor,algebraic-data-types,category-theory,Haskell,Recursion,Functor,Algebraic Data Types,Category Theory,最近我在这里问了以下问题,询问如何为任意多态ADT(代数数据类型),如列表、树等创建通用映射函数和Functor的通用实例: 现在,我正试图重新格式化上述内容,使之与递归方案兼容。也就是说,我想一方面定义类型,另一方面定义基函子,并使用base族类型将它们关联起来,而不是定义基函子,然后将类型定义为其固定点 因此,与其这样做,不如: data ListF a b = NilF | ConsF a b newtype Fix f = Fix { unFix :: f (Fix f) } type

最近我在这里问了以下问题,询问如何为任意多态ADT(代数数据类型),如列表、树等创建通用映射函数和
Functor
的通用实例:

现在,我正试图重新格式化上述内容,使之与
递归方案兼容。也就是说,我想一方面定义类型,另一方面定义基函子,并使用
base
族类型将它们关联起来,而不是定义基函子,然后将类型定义为其固定点

因此,与其这样做,不如:

data ListF a b = NilF | ConsF a b
newtype Fix f = Fix { unFix :: f (Fix f) }
type List a = Fix (ListF a)
我想这样做:

data ListF a b = NilF | ConsF a b
data List a = Nil | Cons a (List a)
type instance Base (List a) = ListF a
通过这种方式,我可以利用
递归方案
库的强大功能,同时仍然能够为这些多态类型中的任何一种定义通用的
fmap
。不仅如此,能够使用“正常”类型,而不是作为固定点的类型同义词,这是一种更愉快的体验

尝试: 最初,我考虑一方面使用
Bifunctor
实例,然后以某种方式强制或使其与相应的
Base
家族实例相等。目前我只能考虑使用
Data.Type.Equality
中的
a:~:b
。到目前为止,我得到的是:

{-# LANGUAGE TypeOperators, Rank2Types #-}
import Data.Bifunctor
import Data.Functor.Foldable
import Data.Type.Equality

gmap :: (Bifunctor p, Foldable (f a), Unfoldable (f b)) => 
        (forall x. p x :~: Base (f x)) -> (a -> b) -> f a -> f b
gmap refl f = cata alg
    where
        alg = embed . 
              castWith (apply refl Refl) . 
              bimap f id . 
              castWith (apply (sym refl) Refl)
但是,我的问题在于试图定义
Functor
的实例。我不知道在定义实例时如何指定这些特定的类型约束。 我在考虑以某种方式创建一个typeclass
Equals
,并执行如下操作:

instance (Bifunctor p, Foldable (f a), Unfoldable (f b), Equals (p a) (Base (f a))) 
    => Functor f where
但我不知道这是否可能,也不知道我是否以正确的方式处理它(例如,我不确定我对
gmap
的定义是否正确)


作为参考,这是原始SO问题中通用
gmap
的定义:


更新: 有人指出,
gmap
的以下定义将更为一般,不需要任何类型级别相等的奇怪应用:

gmap :: (Foldable t, Unfoldable d, Bifunctor p, Base d ~ p b, Base t ~ p a)
        => (a -> b) -> t -> d
gmap f = cata ( embed . bimap f id )
然而,我仍然找不到一种方法来创建具有类似类型约束的
Functor
的实例,只要您对
不可判定的实例
没有意见,我就能够拼凑出一个有效的版本

这个想法是通过要求所有x的
,从
gmap
的上下文中删除对
a
b
的所有引用。可折叠(f x)
等,使用软件包编码:

有了
a
b
,我们可以把
gmap
变成
fmap

{-# LANGUAGE UndecidableInstances #-}
instance (Bifunctor p, ForallF Foldable f, ForallF Unfoldable f, Forall (Based p f)) => Functor f where
    fmap = gmap
编辑以添加:上述实例的问题在于它将匹配正确类型的任何类型,如@gonzaw:所述,如果您有

data ListT a = NilT
             | ConsT a (ListT a)

data ListF a b = NilF
               | ConsF a b

type instance Base (ListT a) = ListF a

instance Bifunctor ListF where ...
instance Functor (ListF a) where ...
instance Foldable (ListT a) where ...
instance Unfoldable (ListT a) where ...
然后你得到了比你预想的更多的东西,并且泛型的
函子
实例和
listfa(!)的实例重叠

您可以再添加一层新类型包装来解决这个问题:如果您有

newtype F f x = F{ unF ::  (f x) }

instance (Bifunctor p, ForallF Foldable f, ForallF Unfoldable f, Forall (Based p f)) => Functor (F f) where
    fmap f = F . gmap f . unF

type ListT' = F ListT
最后进行以下类型检查:

*Main> unF . fmap (+1) . F $ ConsT 1 $ ConsT 2 NilT
ConsT 2 (ConsT 3 NilT)

您是否可以接受这层额外的
newtype
包装,这是您必须决定的事情。

1。
:~:
的意义是什么?如果必须始终使用
Refl
调用函数,则该函数可能不实用。2.如果我写
gmap f=cata(embed.bimap f id)
并让编译器推断类型,我得到
(可折叠的t,可展开的d,双函数p,基d~pb,基t~pa)=>(a->b)->t->d
。这种最普通的类型有什么问题吗?如果你喜欢,你可以有一个更具体的类型。编译器对你的函数非常满意,所以我不知道实际的问题是什么。@user2405038我想用
fmap=gmap
创建一个
Functor
的实例!不过这只是个小怪癖。我试图用一个典型的列表类型来测试这一点,比如说
datalistta=consta(listta)|NilT
datalistfab=NilF | consfab
类型实例库(listta)=listfa
。我创建了一个
Bifunctor
的实例,当我尝试创建一个
实例可折叠(ListT a)时,其中
出现以下错误:
无法将类型“Base(ListF a Data.Constraint.Forall.a)”与“p1 Data.Constraint.Forall.a”匹配,类型变量p1不明确
。我使用了
可展开的
,这是因为可怕的
函子
实例不仅与
列表
匹配,还与
列表
匹配……太好了,现在它可以工作了!我不介意新型包装。从我所读到的内容来看,最好的做法是使用一个新的类型包装器,使这些常见类型类(Applicative、Functor、Monad)的“外来”自动类型的实例,以防止孤立实例等。在使用
ListT
时,我总是可以单独使用
gmap
,但是如果我需要使用
Functor
的功能,我只需要快速包装和打开它。如果它让我那么烦恼的话,我只想包括一个快速的
实例函子列表,其中fmap f=unF。FMAPF。事实上,我想知道是否可以使用Template Haskell来包含那个小的
Functor ListT
实例。无论类型如何,该定义都是相同的。如果我有另一种类型,比如
TreeT
,它仍然是
fmap f=unF。fmap f。F
,对吗?如果是这样的话,我想我可以试一下!抱歉三重发布,但这是一个好功能,包括在递归方案库中吗?
newtype F f x = F{ unF ::  (f x) }

instance (Bifunctor p, ForallF Foldable f, ForallF Unfoldable f, Forall (Based p f)) => Functor (F f) where
    fmap f = F . gmap f . unF

type ListT' = F ListT
*Main> unF . fmap (+1) . F $ ConsT 1 $ ConsT 2 NilT
ConsT 2 (ConsT 3 NilT)