В статье (и соответствующем отрывке из Викиучебника ) говорится о том, как эффекты (или, если использовать там язык, контексты) аппликативных значений можно комбинировать моноидально. Связь с Foldable
заключается в том, что сворачивание в виде списков в конечном итоге сводится к моноидальному объединению значений (см. ответ Чепнера , а также Foldr / Foldl бесплатно, когда Tree реализует Foldable foldmap? . Что касается аппликативной части контекста, есть несколько способов посмотреть на это. Один из них отмечает, что для любых Applicative f
и Monoid m
, f m
является моноидом, с pure mempty
как mempty
и liftA2 mappend
как mappend
( этот Ap
тип из редуктора пакет свидетельствует об этом). Для конкретного примера давайте выберем f ~ Maybe
и m ~ ()
. Это оставляет нам четыре возможных комбинации:
liftA2 mappend (Just ()) (Just ()) = Just ()
liftA2 mappend (Just ()) Nothing = Nothing
liftA2 mappend Nothing (Just ()) = Nothing
liftA2 mappend Nothing Nothing = Nothing
Теперь контрастируйте с All
, моноидом Bool
с (&&)
как mappend
:
mappend (All True) (All True) = All True
mappend (All True) (All False) = All False
mappend (All False) (All True) = All False
mappend (All False) (All False) = All False
Они идеально соответствуют: Just ()
означает True
, Nothing
для False
и liftA2 mappend
для (&&)
.
Теперь давайте еще раз посмотрим на пример Wikibook:
deleteIfNegative :: (Num a, Ord a) => a -> Maybe a
deleteIfNegative x = if x < 0 then Nothing else Just x
rejectWithNegatives :: (Num a, Ord a, Traversable t) => t a -> Maybe (t a)
rejectWithNegatives = traverse deleteIfNegative
GHCi> rejectWithNegatives [2,4,8]
Just [2,4,8]
GHCi> rejectWithNegatives [2,-4,8]
Nothing
Значения Maybe
, сгенерированные путем применения deleteIfNegative
к значениям в списках, моноидально объединяются, как показано выше, так что мы получаем Nothing
, если только all значения Maybe
Just
.
К этому вопросу также можно подойти в противоположном направлении. Через экземпляр Applicative
для Const
...
-- I have suppressed a few implementation details from the instance used by GHC.
instance Monoid m => Applicative (Const m) where
pure _ = Const mempty
Const x <*> Const y = Const (x `mappend` y)
... мы можем получить Applicative
из любого Monoid
, так что (<*>)
объединяет моноидальные значения моноидально. Это позволяет определять foldMap
и друзей в терминах traverse
.
В заключение отметим, что теоретическое описание категории Applicative
как класса для моноидальных функторов включает нечто весьма отличное от того, что я рассмотрел здесь. Для дальнейшего обсуждения этого вопроса и других мелких шрифтов см. Моноидальный функтор применим, но где находится класс типов моноидов в определении Applicative? (если вы хотите копать глубже, стоит прочитать все ответы там).