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

Почему Клейсли не является примером Моноида?

Если вы хотите добавить две функции типа (a → m b), чтобы вы получили только одну функцию того же типа, добавляющую оба результата, вы можете использовать Kleisli для этого:

instance (Monad m, Monoid b) => Monoid (Kleisli m a b) where
    mempty = Kleisli (\_ -> return mempty)
    mappend k1 k2 =
        Kleisli g
            where
                g x = do
                    r1 <- runKleisli k1 x
                    r2 <- runKleisli k2 x
                    return (r1 <> r2)

Однако в настоящее время такой экземпляр не указан в Control.Arrow. Как часто, в Haskell, я подозреваю, что есть веская причина, но не могу найти, какой из них.

Примечание

Этот вопрос скорее похож на на этот. Однако с Monoid я не вижу способа определить экземпляр, например:

instance (Monad m, Monoid b) => Monoid (a -> m b) where
    [...]

поскольку уже есть экземпляр:

instance Monoid b => Monoid (a -> b) where
    [...]
4b9b3361

Ответ 1

В бизнесе дизайна библиотеки мы сталкиваемся с выбором здесь, и мы решили быть менее чем полностью последовательными в нашей коллективной политике (или ее отсутствии).

Monoid экземпляры для конструкторов типа Monad (или Applicative) могут возникать различными способами. Потоковый подъем всегда доступен, но мы не определяем

instance (Applicative f, Monoid x) => Monoid (f x) {- not really -} where
  mempty         = pure mempty
  mappend fa fb  = mappend <$> fa <*> fb

Заметим, что instance Monoid (a -> b) является именно таким поточечным поднятием, поэтому поточечный подъем для (a -> m b) происходит всякий раз, когда моноидный экземпляр для m b делает поточечный подъем для моноида на b.

Мы не делаем поточечного подъема в целом не только потому, что он предотвращал бы другие экземпляры Monoid, носители которых были бы применимыми типами, но также потому, что структура f часто считается более значительной, чем структура x. Ключевым случаем является свободный моноид, более известный как [x], который является Monoid на [] и (++), а не поточечным подъемом. Моноидальная структура исходит из обертывания списка, а не из обернутых элементов.

Мое предпочтительное эмпирическое правило действительно определяет приоритетность моноидальной структуры, присущей конструктору типа, либо поточечного подъема, либо моноидальной структуры конкретных экземпляров типа, как моноидный состав для a -> a. Они могут и могут получить обертки newtype.

Аргументы разрываются над тем, должен ли Monoid (m x) совпадать с MonadPlus m, когда оба существуют (и аналогично с Alternative). Я считаю, что единственным хорошим экземпляром MonadPlus является экземпляр экземпляра Monoid, но другие отличаются. Тем не менее, библиотека несовместима в этом вопросе, особенно не в связи с тем (многие читатели увидели бы этот старый жучок на моем пути)...

... экземпляр monoid для Maybe, который игнорирует тот факт, что мы обычно используем Maybe для моделирования возможного сбоя и вместо этого наблюдаем, что для того, чтобы дать представление о типе данных о том, как вырезать дополнительный элемент, можно использовать полугруппа - нейтральный элемент, если она еще не имеет этого. Две конструкции порождают изоморфные типы, но они не являются концептуально родственными. (Изменить). Хуже того, идея выполняется неловко, предоставляя экземпляр ограничения Monoid, когда требуется только Semigroup. Я хотел бы видеть Semigroup -extends- to-Monoid реализована, но не для Maybe.)

Возвращаясь к Kleisli, в частности, у нас есть три очевидных экземпляра-кандидата:

  • Monoid (Kleisli m a a) с return и композицией Клейсли
  • MonadPlus m => Monoid (Kleisli m a b) поднять mzero и mplus поточечно над ->
  • Monoid b => Monoid (Kleisli m a b) поднимая моноидную структуру b над m, тогда ->

Я ожидаю, что выбор не был сделан, просто потому, что он не понял, какой выбор сделать. Я стесняюсь сказать это, но мой голос будет равен 2, указав приоритет структуры, исходящей от Kleisli m a по структуре, исходящей от b.