13

モナドのソースを見てください:

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

私の知る限り、「追加の」機能を含める主な理由は2つあります。

  • 効率:非効率的なジェネリック実装が存在する場合があり、クラスの作成者は、インスタンス固有の実装が大幅に優れていると期待しています。このような場合、デフォルトの実装でクラスに関数を含めることは、インスタンスが必要に応じて最適化されたバージョンを使用できることを意味しますが、必須ではありません。この楽しい例については、をご覧くださいFoldable。これはにも当てはまりますMonad

  • 実装の選択:多くの場合、使用できるクラス関数のサブセットがいくつかあります。すべての潜在的な関数を含み、相互にデフォルトの実装を使用することは、インスタンスがいくつかの関数を選択して実装し、残りを自動的に取得できることを意味します。これはにも当てはまりますFoldableEq、より簡単な例です。

于 2012-09-20T15:23:16.773 に答える
3

このように、カスタム>>はモナドに実装でき、経由よりも効率的または自然に実行できますm >>= \_ -> kが、デフォルトの実装は引き続き存在します。

于 2012-09-20T15:20:41.400 に答える
3

型クラスにメソッドを含めるためのもう1つの議論は、メソッドが特定の法則を満たす必要がある場合、またはそれらの法則のステートメントをより明確にする場合です。私は、法則が型クラスに道徳的に関連付けられるべきであると主張します(「このクラスのインスタンスを宣言するために何を提供する必要がありますか?」returnjoinfmapよりreturn>>=; これにより、4つの演算子すべてを型クラスに入れて(そして!Monadのサブクラスを作成してFunctor)、のデフォルト定義を与える>>=ことをお勧めします。joinその逆も同様です。`

于 2012-09-27T07:44:06.430 に答える