在类型类定义中添加附加函数/组合器的优缺点是什么?

时间:2012-09-20 15:14:53

标签: haskell typeclass

查看source for 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

3 个答案:

答案 0 :(得分:13)

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

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

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

答案 1 :(得分:3)

这样,自定义>>可以为monad实现,可以通过m >>= \_ -> k更高效或自然地完成,但默认实现仍然存在。

答案 2 :(得分:3)

在类型类中包含方法的另一个论点是,它们应该满足某些法律,或者当它们使这些法律的陈述更清楚时。我认为法律应该在道德上与类型类相关联(“为了声明这个类的实例,我必须提供什么?”)例如,你可能更愿意用{{1}来陈述monad定律。 },returnjoin,而不是fmapreturn;鼓励您将所有四个运算符放在类型类中(并使>>=成为Monad的子类!),并根据Functor>>=给出join的默认定义反之亦然。