(.)
和(<=<)
非常相似:
(.) :: (b -> c) -> (a -> b) -> (a -> c)
(<=<) :: Monad m => (b -> m c) -> (a -> m b) -> (a -> m c)
并且可以作为Category
类型类((->)
和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
是否有一个类型类抽象出这些应用程序函数?
答案 0 :(得分:3)
正如丹尼尔的评论所说,(int*)ap
已经包含 %1 = tail call i8* @malloc(i64 4)
...
%8 = tail call i32 (i8*, ...) @printf(i8* nonnull getelementptr inbounds ([10 x i8], [10 x i8]* @.str.1, i64 0, i64 0), i8* %1, i8* %1, i8* %1)
。已经存在一个新类型(类似(=<<)
($)
Kleisli
a -> m b
的{{1}}新类型Category
a
名为Identity
,其Monad
f $ x
Identity . f =<< Identity x
对应
(.)
虽然有些子组件在(<=<)
和a -> b
中重复使用(前者为a -> m b
,后者为a :: * -> * -> *
),但可以将其抽象为类型类对于类型构造函数Category
(原来是($)
),(=<<)
和a
中最大的此类子组件在前者中仅为m a
且{ {1}}在后者中。
答案 1 :(得分:2)
您的示例都是仿函数的箭头映射(不是Functors
,而是更广泛的分类意义上的仿函数),就像fmap
是Functor
的箭头映射一样。例如,(=<<)
是针对某些monad Kleisli m
的仿函数从(->)
到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
类别而言,可能会为(<*>)
编写类似的实例。对于($)
,它是(->)
中标识仿函数的箭头映射,因此fmap
仅Identity
没有Identity
包装器(cf丹尼尔瓦格纳对这个问题的评论。