为什么Control.Arrow中的Kleisli没有Functor实例?

8

在尝试熟悉Control.Arrow时,我注意到Kleisli newtype似乎可以接受一个Functor实例,类似于:

instance Monad m => Functor (Kleisli m a) where
    fmap f (Kleisli k) = Kleisli $ liftM f . k

为什么没有提供这个实例?它作为孤立实例存在于某个包中吗?


我敢打赌,一旦你对于一个单子m有了a -> m b的理解,使用Kleisli进行包装并不会添加任何新的东西 - 除了将liftM暴露为Functor的fmap。 - Sassa NF
2个回答

7
每个箭头都可以通过定义成为有效的Functor。
fmap f a = a >>> arr f

然而,因为它们的种类不同(Functor需要* -> *,而Arrow需要* -> * -> *),所以不可能声明FunctorArrow的超类。因此,每个箭头需要单独定义实例。
您可以使用ArrowMonad包装任何箭头,然后给出一个Applicative实例(因此也是一个Functor):instance Arrow a => Applicative (ArrowMonad a) where ...
我不认为Kleisli缺少Functor实例有任何特别的原因。最有可能的原因似乎是您不需要它。如果您想使用函子(或应用程序或单调)操作,则在原始单调值上执行操作。只有当您需要箭头界面时才将单调值包装到Kleisli中。

在我的一个个人项目中,我需要使用带有Kleisli箭头的Free monad作为functor,因此我不能直接在原始monad中工作。 - danidiaz
@DanielDíazCarrete 最简单的方法可能是自己创建一个孤立实例:instance (Monad m) => Functor (Kleisli m a) where fmap = (^<<)。或者建议在Haskell libraries中添加Functor实例。 - Petr

1

更新

Control.Arrow中已经定义:

(>>^) :: Arrow a => a b c -> (c -> d) -> a b d
(^<<) :: Arrow a => (c -> d) -> a b c -> a b d

更新2

如果你希望将Free Monad插入到Kleisli中,那是不可能的,因为Free有一个额外的参数f

所以你需要使用Arrow Transformer或者创建一个新的Arrow类,例如:

class Arrow a => ArrowFunctor f a | a -> f where
    afmap :: a b (f c)

软件包 arrows包含一些示例,但它没有实现Free


5
我不明白这如何有助于回答问题。 - Philip JF
关于更新#2,我的意思是类似于“type FKleisli o = Free (Kleisli o)”这样的东西。 - danidiaz
@Daniel:当然,你还需要创建 newtype FKleisli f m a b = FKleisli { runFKleisli :: a -> m (f b) },最后添加 instance (Functor f, Monad m, MonadFree f m) => ArrowFunctor (FKleisli f m a) where ... - wit

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接