答案就在下面(全部来自Control.Arrow docs)
newtype ArrowApply a => ArrowMonad a b = ArrowMonad (a () b)
instance Monad ArrowApply a => Monad (ArrowMonad a)
ArrowMonad newtype 是我们为ArrowApply 箭头定义Monad 实例的载体。我们本来可以使用
instance Monad ArrowApply a => Monad (a ())
但这会导致 Haskell 的有限类型类推断出现问题(我理解它可以与 UndecideableInstances 扩展一起使用)。
您可以将ArrowApply 箭头的Monad 实例视为将单元操作转换为等效的箭头操作,如源代码所示:
instance ArrowApply a => Monad (ArrowMonad a) where
return x = ArrowMonad (arr (\_ -> x))
ArrowMonad m >>= f = ArrowMonad (m >>>
arr (\x -> let ArrowMonad h = f x in (h, ())) >>>
app)
所以知道我们知道ArrowApply 与Monad 一样强大,因为我们可以在其中实现所有Monad 操作。令人惊讶的是,反过来也是如此。这是由@hammar 指出的Kleisli newtype 给出的。观察:
newtype Kleisli m a b = Kleisli { runKleisli :: a -> m b }
instance Monad m => Category (Kleisli m) where
id = Kleisli return
(Kleisli f) . (Kleisli g) = Kleisli (\b -> g b >>= f)
instance Monad m => Arrow (Kleisli m) where
arr f = Kleisli (return . f)
first (Kleisli f) = Kleisli (\ ~(b,d) -> f b >>= \c -> return (c,d))
second (Kleisli f) = Kleisli (\ ~(d,b) -> f b >>= \c -> return (d,c))
instance Monad m => ArrowApply (Kleisli m) where
app = Kleisli (\(Kleisli f, x) -> f x)
instance Monad m => ArrowChoice (Kleisli m) where
left f = f +++ arr id
right f = arr id +++ f
f +++ g = (f >>> arr Left) ||| (g >>> arr Right)
Kleisli f ||| Kleisli g = Kleisli (either f g)
前面给出了所有使用 monad 操作的常用箭头操作的实现。 (***) 没有被提及,因为它在 first 和 second 中有一个默认实现:
f *** g = first f >>> second g
所以现在我们知道如何使用 Monad 操作来实现箭头(Arrow、ArrowChoice、ArrowApply)操作。
回答您关于为什么我们同时拥有Monad 和Arrow 的问题,如果它们是等价的:
当我们不需要 monad 的全部功能时,功能较弱的箭头很有用,就像应用函子很有用一样。尽管ArrowApply 和Monad 是等价的,但没有app 的Arrow 或ArrowChoice 在Monad 层次结构中是无法表示的。反之亦然,Applicative 在箭头层次结构中不可表示。
这是因为ap 在 monad 层次结构中是“第一”,而在箭头层次结构中是“最后”。
monad 和箭头世界之间的主要语义区别在于箭头捕获转换(arr b c 意味着我们从 b 生成 c),而 monad 捕获操作(monad a 生成 @987654357 @)。这种差异在Kleisli 和ArrowMonad 新类型中得到了很好的体现:
newtype Kleisli m a b = Kleisli { runKleisli :: a -> m b }
newtype ArrowApply a => ArrowMonad a b = ArrowMonad (a () b)
在Kleisli 中我们必须添加源类型a,在ArrowMonad 中我们将其设置为()。
希望你满意!