GHC 8.6+ предоставляют другой способ сделать это, возможно, более прямой.Он добавил новый тип Ap
к Data.Monoid
, который обрабатывает случай подъема экземпляра Monoid
внутреннего типа над контекстом Applicative
.
$ghci
GHCi, version 8.6.1: http://www.haskell.org/ghc/ :? for help
Prelude> import Data.Monoid
Prelude Data.Monoid> :t getAp . foldMap Ap
getAp . foldMap Ap
:: (Foldable t, Applicative f, Monoid a) => t (f a) -> f a
Это обобщает[State String [a]] -> State String [a]
в довольно минимальной форме.Фактически, избегая sequence
, это снижает требование Traversable
до Foldable
.(Ограничение Monad
на sequence
является историческим артефактом, и sequenceA
существует, чтобы снизить его до Applicative
, поэтому я не беспокоюсь о разнице там.) Этот подход имеет дополнительное незначительное эксплуатационное отличие по сравнению с использованиемsequence
- объединяет моноидальное соединение и аппликативную последовательность в один проход.Будут некоторые комбинации типов, где это более эффективно, и комбинации типов, где это может быть менее эффективно из-за ассоциативности.Это зависит от того, имеет ли mappend
смещение ассоциативности, которое соответствует смещению, которое создает foldMap
.