答案如下(所有这些都来自Control.Arrow 文档)
newtype ArrowApply a => ArrowMonad a b = ArrowMonad (a () b)
instance Monad ArrowApply a => Monad (ArrowMonad a)
newtypeArrowMonad
是我们用来定义箭头Monad
实例的车辆。ArrowApply
我们本可以使用
instance Monad ArrowApply a => Monad (a ())
但这会导致 Haskell 的有限类型类推断出现问题(UndecideableInstances
我理解它可以与扩展一起使用)。
您可以将箭头的Monad
实例ArrowApply
视为将一元操作转换为等效的箭头操作,如源代码所示:
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
在其中实现所有操作。令人惊讶的是,反过来也是如此。这是由Kleisli
@hammar 指出的新类型给出的。观察:
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
andMonad
是等价的,an Arrow
or ArrowChoice
without是在层次结构app
中不可表示的东西。Monad
反之亦然,anApplicative
在箭头层次结构中不可表示。这是因为ap
在单子层次结构中出现“第一”,在箭头层次结构中出现“最后”。
monad 和箭头世界之间的主要语义区别在于,箭头捕获转换(arr b c
意味着我们c
从 a 产生 a b
),而 monad 捕获操作(monad a
产生 an a
)。这种差异在Kleisli
和ArrowMonad
newtypes 中得到了很好的体现:
newtype Kleisli m a b = Kleisli { runKleisli :: a -> m b }
newtype ArrowApply a => ArrowMonad a b = ArrowMonad (a () b)
在Kleisli
我们必须添加源类型a
,并在ArrowMonad
我们将其设置为()
.
我希望这能让你满意!