Haskell 具有不同单体结构的Lax单体函子
应用函子因其在有效上下文中应用函数的能力而在Haskeller中广为人知并深受喜爱 从范畴论的角度来看,Haskell 具有不同单体结构的Lax单体函子,haskell,functor,applicative,category-theory,alternative-functor,Haskell,Functor,Applicative,Category Theory,Alternative Functor,应用函子因其在有效上下文中应用函数的能力而在Haskeller中广为人知并深受喜爱 从范畴论的角度来看,的方法是实用的: pure :: a -> f a (<*>) :: f (a -> b) -> f a -> f b 其思想是,要编写纯只需将单元中的()替换为给定值,要编写()只需将函数和参数压缩成一个元组,然后在元组上映射合适的应用程序函数 此外,这种对应关系将应用的定律转化为关于单位和(**)的自然单倍体ish定律,因此事实上,应用函子正是范畴理论
的方法是实用的
:
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
其思想是,要编写纯
只需将单元
中的()
替换为给定值,要编写()
只需将函数和参数压缩成一个元组,然后在元组上映射合适的应用程序函数
此外,这种对应关系将应用的
定律转化为关于单位
和(**)
的自然单倍体ish定律,因此事实上,应用函子正是范畴理论家所称的松弛单倍体函子(松弛,因为(**)
仅仅是一种自然变换,而不是同构)
好的,很好,很好。这是众所周知的。但这只是一个松弛幺半函子族——它们尊重乘积的幺半结构。lax幺半函子在源函数和目标函数中包含两种幺半结构选择:如果将乘积转化为和,则得到如下结果:
class PtS f where
unit :: f Void
(**) :: f a -> f b -> f (Either a b)
-- some example instances
instance PtS Maybe where
unit = Nothing
Nothing ** Nothing = Nothing
Just a ** Nothing = Just (Left a)
Nothing ** Just b = Just (Right b)
Just a ** Just b = Just (Left a) -- ick, but it does satisfy the laws
instance PtS [] where
unit = []
xs ** ys = map Left xs ++ map Right ys
由于unit::Void->f Void
是唯一确定的,所以将求和转换为其他的幺半群结构似乎变得不那么有趣,所以实际上有更多的半群在进行。但仍然:
- 像上面这样的lax幺半函子是研究过的还是有用的
- 是否有像
这样的简洁的替代演示文稿Applicative
作为标识()
作为bifunctor(,)
- 识别同构类型,即
和(a,())≅ ((),a)≅ a
(a,(b,c))≅ ((a,b),c)
()
交换为Void
和(,)
交换为或时,它也是一个幺半类
然而,单像线并不能让你走得很远,Hask之所以如此强大,是因为它是。这就给了我们咖喱和相关的技术,没有这些技术,应用程序将毫无用处
当一个单倍体范畴的恒等式是A时,它可以是笛卡尔闭的,即一个存在一个正的类型(当然,我们忽略它)⟂ 这里)箭头。对于任何类型的A
,都有一个函数A->()
,即const()
。但是,没有函数A->Void
。相反,Void
是初始对象:它正好存在一个箭头,即荒谬的::Void->a
方法。这样的单倍体范畴在当时是不能笛卡尔封闭的。
当然,现在你可以通过旋转箭头方向在初始和终端之间轻松切换。这总是把你置于双重结构中,所以我们得到一个。但这意味着您还需要翻转单倍体函子中的箭头。这些被称为(并概括为comonads)。有了Conor令人惊叹的命名方案
class (Functor f) => Decisive f where
nogood :: f Void -> Void
orwell :: f (Either s t) -> Either (f s) (f t)
我在范畴理论方面的背景非常有限,但你们的PtS课程FWIW让我想起了,基本上是这样的:
class Applicative f => Alternative f where
empty :: f a
(<|>) :: f a -> f a -> f a
class Applicative f=>备选方案f其中
空::f a
()::fa->fa->fa
当然唯一的问题是,Alternative
是Applicative
的扩展。然而,也许有人可以想象它是单独呈现的,与Applicative
的组合让人想起一个具有非交换环状结构的函子,两个幺半群结构作为环的运算?Applicative
和Alternative
IIRC之间也存在分配规律。Applicative
的“整洁替代表示”基于以下两个等价关系
pure a = fmap (const a) unit
unit = pure ()
ff <*> fa = fmap (\(f,a) -> f a) $ ff ** fa
fa ** fb = pure (,) <*> fa <*> fb
替换为纯
,我们可以将类型()
和构造函数():()
替换为以恢复单元
pure :: a -> f a
pure () :: f ()
同样地(虽然不是那么简单)将类型(a,b)
和构造函数(,)::a->b->(a,b)
替换为liftA2
,以恢复**
liftA2 :: (a -> b -> c) -> f a -> f b -> f c
liftA2 (,) :: f a -> f b -> f (a,b)
Applicative
然后通过将函数application($)::(a->b)->a->b
提升到函子中来获取nice
操作符
(<*>) :: f (a -> b) -> f a -> f b
(<*>) = liftA2 ($)
操作人员
我们想找到(**)
的替代方案。除了像或
这样的总和之外,还有一种替代方法,可以将它们作为乘积的函数写入。在不存在求和的面向对象编程语言中,它显示为访问者模式
data Either a b = Left a | Right b
{-# LANGUAGE RankNTypes #-}
type Sum a b = forall c. (a -> c) -> (b -> c) -> c
如果您更改了的参数的顺序并部分应用它们,您将得到这样的结果
either :: (a -> c) -> (b -> c) -> Either a b -> c
toSum :: Either a b -> Sum a b
toSum e = \forA forB -> either forA forB e
toEither :: Sum a b -> Either a b
toEither s = s Left Right
我们可以看到,a或b≅ 求和a b
。这允许我们重写(**)
现在很清楚**
的作用。它延迟fmap
在它的两个参数上添加某些内容,并将这两个映射的结果组合在一起。如果我们引入一个新操作符,::fc->fc->fc
,它简单地假设fmap
已经完成,那么我们可以看到
fmap (\f -> f forA forB) (fa ** fb) = fmap forA fa <||> fmap forB fb
因此,我们可以用下面的类来表示PtS
可以表示的所有内容,并且可以实现PtS
的所有内容都可以实现下面的类:
class Functor f => AlmostAlternative f where
empty :: f a
(<||>) :: f a -> f a -> f a
所有a的。幺半群(fa)
约束是伪码;我不知道如何在Haskell中表达这样的约束。我知道这并不能真正回答您的问题。在某种程度上,一个幺半函子WRT余积可能仍然很有趣,但我想像unit
这样的麻烦就像你说的那样微不足道,这在很大程度上阻碍了这一点。我知道你必须这样做
either :: (a -> c) -> (b -> c) -> Either a b -> c
toSum :: Either a b -> Sum a b
toSum e = \forA forB -> either forA forB e
toEither :: Sum a b -> Either a b
toEither s = s Left Right
(**) :: f a -> f b -> f (Either a b)
(**) :: f a -> f b -> f (Sum a b)
(**) :: f a -> f b -> f ((a -> c) -> (b -> c) -> c)
fmap (\f -> f forA forB) (fa ** fb) = fmap forA fa <||> fmap forB fb
fa ** fb = fmap Left fa <||> fmap Right fb
fa1 <||> fa2 = fmap (either id id) $ fa1 ** fa2
class Functor f => AlmostAlternative f where
empty :: f a
(<||>) :: f a -> f a -> f a
class (Functor f, forall a. Monoid (f a)) => MonoidalFunctor f