Arrows
由类别概括,因此由类型类概括Category
。
class Category f where
(.) :: f a b -> f b c -> f a c
id :: f a a
Arrow
类型类定义Category
作为超类。类别(在haskell 意义上)概括了函数(您可以组合它们但不能应用它们),因此绝对是“计算模型”。 为处理元组Arrow
提供了额外的结构。Category
因此,虽然Category
反映了有关 Haskell 函数空间的某些内容,但Arrow
将其扩展到有关产品类型的某些内容。
每一个Monad
都会产生一个叫做“Kleisli 类别”的东西,这个结构给你提供了ArrowApply
. 你可以建立一个完整的循环不会改变你的行为Monad
的任何东西ArrowApply
,所以从某种意义上说Monad
,ArrowApply
它们是一回事。
newtype Kleisli m a b = Kleisli { runKleisli :: a -> m b }
instance Monad m => Category (Kleisli m) where
id = Kleisli return
(Kleisli f) . (Kleisli g) = Kleisli (\b -> g b >>= f)
instance Monad m => Arrow (Kleisli m) where
arr f = Kleisli (return . f)
first (Kleisli f) = Kleisli (\ ~(b,d) -> f b >>= \c -> return (c,d))
second (Kleisli f) = Kleisli (\ ~(d,b) -> f b >>= \c -> return (d,c))
实际上,除了超类之外,每一个Arrow
都会产生一个(普遍量化以得到正确的种类) ,我相信适当的组合和足以重建你的. Applicative
Category
Category
Applicative
Arrow
因此,这些结构是紧密相连的。
警告:前面有空洞的评论。Functor
/ Applicative
/Monad
思维方式和Category
/思维方式之间的一个主要区别Arrow
是,虽然Functor
及其同类是对象级别的概括(Haskell 中的类型),Category
/是态射Arrow
概念的泛化(Haskell 中的函数)。我的信念是,在广义态射层面上的思考比在广义对象层面上的思考涉及更高层次的抽象。有时这是一件好事,有时则不是。另一方面,尽管有分类基础,但数学界没有人认为Arrows
Applicative
很有趣,我的理解Applicative
通常比Arrow
.
基本上你可以想到“Category < Arrow < ArrowApply”和“Functor < Applicative < Monad”,例如“Category ~ Functor”、“Arrow ~ Applicative”和“ArrowApply ~ Monad”。
下面更具体:
至于建模计算的其他结构:通常可以将分类构造中的“箭头”(此处仅表示态射)的方向反转以获得“对偶”或“共构造”。所以,如果一个单子被定义为
class Functor m => Monad m where
return :: a -> m a
join :: m (m a) -> m a
(好吧,我知道这不是 Haskell 定义事物的方式,但它ma >>= f = join $ fmap f ma
也join x = x >>= id
可能是这样)然后comonad 是
class Functor m => Comonad m where
extract :: m a -> a -- this is co-return
duplicate :: m a -> m (m a) -- this is co-join
事实证明,这件事也很常见。原来这Comonad
是元胞自动机的基本底层结构。为了完整起见,我应该指出 Edward Kmett在函子和“可扩展函子”之间Control.Comonad
放置duplicate
了一个类,因为您还可以定义Comonad
extend :: (m a -> b) -> m a -> m b -- Looks familiar? this is just the dual of >>=
extend f = fmap f . duplicate
--this is enough
duplicate = extend id
原来所有Monad
的s也是“可扩展的”
monadDuplicate :: Monad m => m a -> m (m a)
monadDuplicate = return
虽然所有人Comonads
都是“可加入的”
comonadJoin :: Comonad m => m (m a) -> m a
comonadJoin = extract
所以这些结构非常接近。