Подтвердить что ты не робот

Каковы плюсы и минусы добавления дополнительных функций/комбинаторов в определение класса?

Глядя на источник для Монады:

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
4b9b3361

Ответ 1

Насколько я знаю, есть две основные причины включения "дополнительных" функций:

  • Эффективность. Иногда существует неэффективная универсальная реализация, и автор класса ожидает, что реализация конкретных экземпляров будет значительно лучше. В таких случаях, включая функцию класса с реализацией по умолчанию, это означает, что экземпляры могут использовать оптимизированные версии, если они этого хотят, но не требуются. Для примера, посмотрите Foldable. Это также относится к Monad.

  • Выбор реализации. Часто существует несколько подмножеств функций класса, которые могут быть использованы; включая все потенциальные функции и использование реализаций по умолчанию в терминах друг друга, означает, что экземпляр может выбрать некоторые функции для реализации и получить остальное автоматически. Это также относится к Foldable, но Eq - более простой пример.

Ответ 2

Таким образом, пользовательский >> может быть реализован для монадов, где это можно сделать более эффективно или естественно, чем через m >>= \_ -> k, но реализация по умолчанию все еще существует.

Ответ 3

Еще один аргумент для включения методов в класс классов - это когда они должны удовлетворять определенным законам или когда они делают утверждение этих законов более ясным. Я бы сказал, что законы должны морально ассоциироваться с классом стилей ( "что я должен предоставить, чтобы объявить экземпляр этого класса?" ) Например, вы можете предпочесть формулировки законов монады в терминах return, join и fmap, а не return и >>=; который побуждает вас поместить все четыре оператора в класс типа (и сделать Monad подкласс Functor!) и дать определения по умолчанию >>= в терминах join и наоборот.