函数和 Kleisli 箭头的应用

Application of functions and Kleisli arrows

(.)(<=<) 非常相似:

(.)   ::            (b ->   c) -> (a ->   b) -> (a ->   c)
(<=<) :: Monad m => (b -> m c) -> (a -> m b) -> (a -> m c)

并且在 Category 类型 class 中作为方法可用((->)Kleisli 实例):

(<<<) :: (Category f) => f b c -> f a b -> f a c

($)(=<<)也很相似:

($)   ::            (a ->   b) ->   a ->   b
(=<<) :: Monad m => (a -> m b) -> m a -> m b

有没有类型class抽象这些应用程序功能?

正如 Daniel 的评论所说,(=<<) 已经包含 ($)。对于 a 已经有一个新类型(类似于 a -> m b 对于 Category 有一个 Kleisli 新类型)叫做 Identity,它有一个 Monad 实例

f $ x

对应于

Identity . f =<< Identity x

(.)(<=<)中有子组件被复用(即前者的a -> b和后者的a -> m b)可以抽象出来类型构造函数 a :: * -> * -> * 的类型类(结果是 Category),($)(=<<) 中最大的此类子组件只是前者中的 am a 在后者中。

你的两个例子都是函子的箭头映射(不是Functors,而是广义上的函子),就像fmapFunctor的箭头映射一样。例如,(=<<) 是某个单子 m 的函子从 Kleisli m(->) 的箭头映射。那么,一种适当的概括是解释不同类别之间的函子。 Control.Categorical.Functor 规定:

class (Category r, Category t) => Functor f r t | f r -> t, f t -> r where
  fmap :: r a b -> t (f a) (f b)

有了它,您将能够本着以下精神编写一个实例:

-- `(.)` is plain old Prelude `(.)`, and not the generalised `Category` one.
instance Monad m => Functor m (Kleisli m) (->) where
    fmap = (=<<) . runKleisli

或者,对于一些你实际上可以 运行:

{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}

import Control.Arrow (Kleisli(..))
import qualified Control.Categorical.Functor as F

newtype BindF m a = BindF { runBindF :: m a }
    deriving (Functor, Applicative, Monad, Show)

instance Monad m => F.Functor (BindF m) (Kleisli (BindF m)) (->) where
    fmap = (=<<) . runKleisli
GHCi> F.fmap (Kleisli (BindF . replicate 2)) (BindF [1,2,3])
BindF {runBindF = [1,1,2,2,3,3]}

可能会根据 Static 类别为 (<*>) 编写类似的实例。至于 ($),它是 (->) 中恒等函子的箭头映射,因此对于 Identity 它只是 fmap 没有 Identity 包装器(cf . Daniel Wagner 对问题的评论)。