我一直在想instance Functor (f :.: g)
的 * 完整的、包罗万象的 * 上下文是什么样的。我脑子里立即冒出的想法是:
newtype (f :.: g) a = Comp (f (g a))
instance (Functor f, Functor g) => Functor (f :.: g) where
fmap f (Comp x) = Comp (fmap (fmap f) x)
但是,两个反变函子也会合成为协变的,就像这样:
instance (Contravariant f, Contravariant g) => Functor (f :.: g) where
fmap f (Comp x) = Comp (contramap (contramap f) x)
这已经不是一个有希望的开始了。然而,我也注意到,从技术上讲,f
和g
甚至不一定要有* -> *
--对f :.: g :: * -> *
的唯一要求是f :: k -> *
和g :: * -> k
对某些k
。这意味着非函子类型可以组合成函子,例如:
newtype Fix f = Fix (f (Fix f))
instance Functor (Fix :.: (,)) where
fmap f (Comp x) = Comp (go x) where
go (Fix (x,xs)) = Fix (f x,go xs)
Fix :.: (,)
同构于Stream
类型:
data Stream a = a :> Stream a
所以这看起来确实是一个不小的问题。这让我思考--如果Haskell的Functor
类型类表示从Hask到Hask的范畴函子,这是否意味着像Fix
和(,)
这样的类型可以是作用于其他范畴的函子?这些范畴会是什么?
1条答案
按热度按时间l7mqbcuq1#
是的,我们可以从构造函数的形状中读出它的意义,我们先来看看
(,)
。(,)
函式这将接受两个类型并生成一个类型。
也就是说,我们可以把这个函数拆开,同时取两个参数。所以
(,)
可以看作是Hask × Hask
到Hask
的函子,其中Hask × Hask
是product category。我们有一个词来描述定义域是两个范畴的乘积的函子。我们称之为双函子,它实际上在base
的Haskell中。具体来说,双函子p
能够将乘积范畴中从(a, b)
到(a', b')
的Map转换为从p a b
到p a' b'
的Map。Haskell的类型类以稍微不同但等效的方式编写此函数拥有一个Map
a -> b
和一个Mapc -> d
完全等价于拥有一个Map(a, c) -> (b, d)
* 在产品类别 * 中。(我的意思是:产品类别中的MapX1 M15 N1 X被 * 定义 * 为MapX1 M16 N1 X和X1 M17 N1 X的产品)。Fix
函数我们可以用同样的方法处理
Fix
。它的形状是
它接受一个单参数类型构造函数并生成一个类型。
现在,在Haskell中,
* -> *
部分可以是 * 任何 * 单参数类型的构造函数,但是绝对地说,使用函子要 * 好 * 得多。(我们很快就会用到),Fix
的* -> *
参数是Functor
,也就是从Hask
到Hask
的函子。在这种情况下,
Fix
就有了从functor categoryHask ^ Hask
到范畴Hask
的函子的正确形状。函子,绝对地,把对象带到对象,把箭头带到箭头,所以让我们一步一步地来。对象部分很简单,我们已经定义过了。具体来说,
Fix
取函子f
(函子是函子范畴的 * 对象 *;如果还没有意义,请再读一遍),并将其Map到我们刚刚定义的类型Fix f
。现在,函子范畴的 * 箭头 * 是natural transformations。给定两个函子
f, g :: C -> D
,从f
到g
的自然变换α
是从C
的 * 对象 * 到D
的 * 箭头 * 的Map。具体地,对于范畴C
中的每个对象x
,α x
应该是D
中从f x
到g x
的箭头,具有以下相干条件:对于
C
中的每个箭头h : x -> y
,我们必须有(g h) . (α x) === (α y) . (f h)
(使用符号如函数组合 * 非常 * 松散,符合真正的范畴论精神)
如图所示,下面必须画一个可交换图,
Haskell实际上并没有一个用于自然变换的内置类型。
这是一个自然变换的形状,当然我们还没有验证它的相干性,所以我们只能相信它满足这个性质。
记住这些抽象的废话,如果
Fix
是从Hask ^ Hask
到Hask
的函子,它应该自然地变换成一个普通的 haskell 函数,它应该有下面的形状。一旦我们有了这个类型,我们就可以很容易地编写实现了。
或者,等价地(根据自然变换的规则),
我不知道这种形式的函子有什么惯用的名字,也不知道有什么类型类包含它,但当然没有什么能阻止你自己创建它。