函数和 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
),($)
和 (=<<)
中最大的此类子组件只是前者中的 a
和 m a
在后者中。
你的两个例子都是函子的箭头映射(不是Functors
,而是广义上的函子),就像fmap
是Functor
的箭头映射一样。例如,(=<<)
是某个单子 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 对问题的评论)。
(.)
和 (<=<)
非常相似:
(.) :: (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
),($)
和 (=<<)
中最大的此类子组件只是前者中的 a
和 m a
在后者中。
你的两个例子都是函子的箭头映射(不是Functors
,而是广义上的函子),就像fmap
是Functor
的箭头映射一样。例如,(=<<)
是某个单子 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 对问题的评论)。