Вот очень простой пример того, что можно сделать с Alternative
:
import Control.Applicative
import Data.Foldable
data Nested f a = Leaf a | Branch (Nested f (f a))
flatten :: (Foldable f, Alternative f) => Nested f a -> f a
flatten (Leaf x) = pure x
flatten (Branch b) = asum (flatten b)
Теперь давайте попробуем то же самое с Monoid
:
flattenMonoid :: (Foldable f, Applicative f) => Nested f a -> f a
flattenMonoid (Leaf x) = pure x
flattenMonoid (Branch b) = fold (flattenMonoid b)
Конечно, это не скомпилируется, потому что в fold (flattenMonoid b)
нам нужно знать, что уплощение создает контейнер с элементами, которые являются экземпляром Monoid
. Итак, давайте добавим, что в контексте:
flattenMonoid :: (Foldable f, Applicative f, Monoid (f a)) => Nested f a -> f a
flattenMonoid (Leaf x) = pure x
flattenMonoid (Branch b) = fold (flattenMonoid b)
Ах, но теперь у нас есть проблемы, потому что мы не можем удовлетворить контекст рекурсивного вызова, который требует Monoid (f (f a))
. Итак, давайте добавим, что в контексте:
flattenMonoid :: (Foldable f, Applicative f, Monoid (f a), Monoid (f (f a))) => Nested f a -> f a
flattenMonoid (Leaf x) = pure x
flattenMonoid (Branch b) = fold (flattenMonoid b)
Ну, что только усугубляет проблему, так как теперь рекурсивные запросы вызова еще вещи, а именно Monoid (f (f (f a)))
...
Было бы здорово, если бы мы могли написать
flattenMonoid :: ((forall a. Monoid a => Monoid (f a)), Foldable f, Applicative f, Monoid (f a)) => Nested f a -> f a
или даже просто
flattenMonoid :: ((forall a. Monoid (f a)), Foldable f, Applicative f) => Nested f a -> f a
и мы можем: instea d написания forall a. Monoid (f a)
, пишем Alternative f
. (Мы можем написать typeclass, который также выражает первое, более легкое для удовлетворения ограничение).
Ах, извините, но это все еще дубликат. Toxaris [перечислены достаточно четко] (http://stackoverflow.com/a/23024217/745903), что вы не можете сделать с «Monoid», в частности, с пунктами 3. и 4 .: «** 3. ** Если мы хотите использовать бесконечно много разных 'a'.MonadPlus m => ...' вместо того, чтобы это невозможно. ** 4. ** Если мы не знаем, что нам нужно. 'MonadPlus m => ...' вместо того, чтобы это невозможно. "Если вам что-то непонятно, спросите конкретно о своих сомнениях. – leftaroundabout
Это просто теоретическое объяснение. Даже там первый комментарий был «Мне бы очень хотелось увидеть конкретный пример здесь». Мне нужны примеры практического кода, которые могут показать, как точно 3 и 4 влияют на использование моноидов. – ais
Хорошо, я понимаю, что вы имеете в виду. Я не думаю, что полезно приготовить некоторые надуманные примеры - конечно, для небольших примеров, которые мы могли бы здесь дать, вы всегда можете сказать _ «теперь почему бы нам просто не разоблачить этот частный тип данных абстрактно? _ Или _» пара ограничений Monoid (f A), Monoid (f B) ', но что?- это не выглядит так «_» или «почему мы не ставим эти бесконечно много/неизвестных типов в экзистенциальную/гадовую обертку» _. Но все эти обходные пути не очень практичны в большом проекте. Просто найдите некоторые библиотечные функции с помощью контекста «Альтернатива» и попробуйте написать их с помощью «Monoid». – leftaroundabout