我想要一个函数,用于将纯函数映射到容器或通过它对应用/ monadic动作进行排序。对于纯映射,我们有
fmap :: Functor f => (a -> b) -> (f a -> f b)
对于monadic测序我们有(来自Data.Taversable)
mapM :: (Traversable f, Monad m) => (a -> m b) -> (f a -> m (f b))
类似于
mapKleisli :: (Traversable f, Monad m) => Kleisli m a b -> Kleisli m (f a) (f b)
mapKleisli = Kleisli . mapM . runKleisli
我们知道( - >)和(Kleisli)都是类别(和箭头)。因此,自然而然地进行推广:
mapCategory :: (X f, Category c) => c a b -> c (f a) (f b)
你知道类似方法的类X吗?也许,在某个地方有hackage?我试过hoogle / hayoo但没找到任何合适的东西。
更新
现在我更清楚自己需要什么。 Kleisli箭头和( - >)都是ArrowApply的实例,它和Monad一样强大。我想出了这个基于箭头的Travesable版本:
{-# LANGUAGE TypeOperators #-}
import Prelude hiding (id, (.), mapM)
import Control.Arrow
import Control.Category
class Traversable f where
traverse :: ArrowApply (~>) => f a -> (a ~> b) ~> f b
mapArrow :: (ArrowApply (~>), Traversable f) => a ~> b -> f a ~> f b
mapArrow a = arr (\x -> (traverse x, a)) >>> app
instance Traversable Maybe where
traverse Nothing = arr (const Nothing)
traverse (Just x) = arr (\a -> (a, x)) >>> app >>> arr Just
instance Traversable [] where
traverse [] = arr (const [])
traverse (x : xs) = undefined -- this is hard!
我可以使用通常的基于Applicative的Traversable,具有纯函数的Identity,但我不确定它是否正常。将纯函数视为monadic动作的特例是很奇怪的。将纯函数和monadic动作解释为某个动作类(Category / Arrow / ArrowApply)的实例对我来说更直接。
问题:您想完成[]
的实例吗?我对ArrowApply和Monad有何看法?
答案 0 :(得分:11)
你要求的是“某些X类”,但应该很清楚,这个类的最正确(或许是唯一)正确的名称是“Functor”。您想要的只是为任意Category
实例定义的仿函数类,而不仅限于(->)
。
当然,您的定义仍局限于(endo)仿函数,从类别到由给定实例的类型构造函数定义的子类别。如果你进一步概括,那么这两个类别没有理由相同,给你a type class something like this one:
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)
与类别理论中的仿函数的完整概念相比,这仍然非常有限,但是很好。
有趣的是,它仍然有一个(->)
类型的构造函数 - 这是因为,即使我们使用任意实例建模源和目标类别,整个事情(特别是,仿函数本身在某种意义上仍然存在于 Hask 中,即与(->)
相关联的类别。对于类型构造函数(->)
,函数的另一半(部件映射对象)粗略地说是* -> *
中的f
。