13

查看 Monad的来源:

class  Monad m  where
    (>>=)       :: forall a b. m a -> (a -> m b) -> m b
    (>>)        :: forall a b. m a -> m b -> m b

    return      :: a -> m a
    fail        :: String -> m a

    {-# INLINE (>>) #-}
    m >> k      = m >>= \_ -> k   -- <-- !! right here !!
    fail s      = error s

您可以看到它>>有一个默认实现。我的问题是,它被认为是好的还是坏的做法,为什么在类型类中包含一个函数/组合器而不是在类型类之外单独提供它?


也就是说,为什么不:

class  Monad m  where
    (>>=)       :: forall a b. m a -> (a -> m b) -> m b

    return      :: a -> m a
    fail        :: String -> m a

    fail s      = error s

和其他地方:

(>>)        :: forall a b. m a -> m b -> m b
{-# INLINE (>>) #-}
m >> k      = m >>= \_ -> k
4

3 回答 3

13

据我所知,包含“额外”功能有两个主要原因:

  • 效率:有时存在效率低下的泛型实现,并且该类的作者期望特定于实例的实现要好得多。在这种情况下,在类中包含具有默认实现的函数意味着实例可以根据需要使用优化版本,但不是必须的。有关这方面的一个有趣示例,请查看Foldable. 这也是如此Monad

  • 实现的选择:通常有几个可以使用的类函数子集;包括所有潜在功能并相互使用默认实现意味着实例可以选择一些功能来实现并自动获取其余功能。这也适用于Foldable,但Eq只是一个更简单的例子。

于 2012-09-20T15:23:16.773 回答
3

在类型类中包含方法的另一个论点是它们何时应该满足某些定律,或者它们何时使这些定律的陈述更清晰。我认为法律应该在道德上与类型类相关联(“我必须提供什么才能声明此类的实例?”)例如,您可能更喜欢用 和 来陈述单子定律returnjoinfmap不是比return>>=; 这鼓励您将所有四个运算符都放在类型类中(并创建Monad一个Functor!的子类),并给出>>=in 的默认定义,join反之亦然。

于 2012-09-27T07:44:06.430 回答
3

这样,>>可以为 monad 实现 custom ,它可以比 via 更有效或更自然地完成m >>= \_ -> k,但仍然存在默认实现。

于 2012-09-20T15:20:41.400 回答