在类别理论中,仿函数是两个类别之间的同态。在Haskell中,它说 applicative functor 允许我们在函子内部应用函数 。是否可以将“函数内的函数”转换回数学或提供其他一些见解? (我知道仿函数可以是Maybe
,[]
等,但仍然难以理解这个概念。)
答案 0 :(得分:6)
我的类别理论根本不强(我从Haskell的编程方面开始,最近一直试图学习其某些概念的类别理论基础)。但这就是我所拥有的:
在Haskell中,仿函数是一种类型构造函数,这意味着它从一般类型映射到“仿函数中的类型”。
在类别理论中,仿函数从一个类别的对象映射到另一个类别的对象。
在将类别理论应用于Haskell时,我们想象我们正在使用类别 Hask ,即Haskell类型的类别。
所以Haskell仿函数不是一般的类别理论仿函数;它们都从 Hask 映射到 Hask 的子类别(因为某个仿函数f a
的类型f
和任意类型{{1} } 仍然是 Haskell类型)。例如,a
仿函数将 Hask 中的对象(类型)映射到Maybe
形式的类型类别。
函数在Haskell中是一流的,因此函数类型是完全普通的类型(并且是 Hask 的对象)所以函子也将函数类型映射到“函数类型仿函数“。因此,短语“仿函数中的函数”是一种类型中值的简写,其类型是将仿函数应用于函数类型。例如Maybe a
是Just (+1)
类型中的一个特定值,它是Maybe (Int -> Int)
仿函数将对象Maybe
映射到的对象(类型)。
因此,“applicative functor”是一个带有一些额外规则的仿函数,这些规则足以获取 values ,它们是作为仿函数“目标”类别对象的类型的函数,并应用于值到目标类别中其他类型的值。
再次使用Int -> Int
作为示例,如果我们只知道它是一个仿函数,它可以让我们在对象Maybe
和Int -> Char
之间以及对象{{1}之间建立对应关系}和Maybe (Int -> Char)
,以及对象Int
和Maybe Int
之间。但是,虽然我们可以使用Char
中的值和Maybe Char
中的值并在Int -> Char
中生成值,但Int
作为仿函数并不能保证我们能够使用Char
中的值和Maybe
中的值执行相应的操作。
当我们也知道它是一个应用仿函数时,我们确实能够在Maybe (Int -> Char)
中获取值并在Maybe Int
中获取值,并在Maybe (Int -> Char)
中生成一个值,这样通过将Maybe Int
值应用于Maybe Char
值来满足某些属性。
据我所知,从纯粹的类别理论角度来看,应用仿函数并不是非常有趣。也许这是因为类别理论关注对象之间的关系,它们对应于Haskell中的类型,但是从编程角度来看,应用函子是由这些类型中的值之间的关系驱动的。 ? (我们希望通过使用仿函数获得的“函数类型”中的值仍然可以应用于要进行计算的事物。)
答案 1 :(得分:3)
翻译回数学
在闭合的幺半群类别中,存在“指数”的概念,其“内化”态射关系。然后,您可以评估这些指数。也就是说,你有一种说法(借口我的想法,Stackoverflow缺少mathjax)
eval : (a ~> b,a) -> b
以及currying和uncurrying的元操作
“applicative functor”以“适用”的方式映射指数,F (a ~> b)
可以与F a
合并以获得F b
。这是因为applicative functor是monoidal functor,所以它们有一个操作(在目标类别中)
f a -> f b -> f (a,b)
当你也使用fmap eval从Haskell给你ap
时。
我怀疑那是有用的,
Haskell
理解应用仿函数的最佳方法是查看类型
class Functor f => Applicative f where
pure :: a -> f a
<*> :: f (a -> b) -> f a -> f b
这个简单的例子是
newtype Id a = Id a
instance Applicative Id where
pure a = Id a
Id f <*> Id a = Id (f $ a)
Id
也是Monad
。事实上,所有Monad
都是Applicative
。
pure = return
mf <*> mx = do f <- mf
x <- mx
return (f x)
一个更有趣的例子是无限序列
data Seq a = Seq a (Seq a)
instance Applicative Seq where
pure a = Seq a (pure a)
(Seq f fs) <*> (Seq x xs) = Seq (f x) (fs <$> xs)
您可以将此视为与列表中的zipWith $
等效。所有Monad
都是Applicative
,但我认为无限序列很有趣,因为相应的monad实例是......非常明显(而且相当慢)。这将留给读者一个练习(顺便说一句,我正在从我记得读过的东西看这个例子/练习,我认为Pigworker在这个网站上写道)。