monoids-0.1.5: Data/Monoid/Applicative.hs
{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, GeneralizedNewtypeDeriving, FlexibleContexts #-}
-----------------------------------------------------------------------------
-- |
-- Module : Data.Monoid.Applicative
-- Copyright : (c) Edward Kmett 2009
-- License : BSD-style
-- Maintainer : libraries@haskell.org
-- Stability : experimental
-- Portability : non-portable (MPTCs)
--
-- Monoids for working with an 'Applicative' 'Functor'.
--
-----------------------------------------------------------------------------
module Data.Monoid.Applicative
( module Data.Monoid.Reducer
, module Data.Ring.Semi.Near
, Traversal(Traversal,getTraversal)
, WrappedApplicative(WrappedApplicative,getWrappedApplicative)
, snocTraversal
) where
import Control.Applicative
import Data.Monoid.Reducer
import Data.Ring.Semi.Near
import Control.Functor.Pointed
-- | A 'Traversal' uses an glues together 'Applicative' actions with (*>)
-- in the manner of 'traverse_' from "Data.Foldable". Any values returned by
-- reduced actions are discarded.
newtype Traversal f = Traversal { getTraversal :: f () }
instance Applicative f => Monoid (Traversal f) where
mempty = Traversal (pure ())
Traversal a `mappend` Traversal b = Traversal (a *> b)
instance Applicative f => Reducer (f a) (Traversal f) where
unit a = Traversal (a *> pure ())
a `cons` Traversal b = Traversal (a *> b)
Traversal a `snoc` b = Traversal (a *> b *> pure ())
{-# RULES "unitTraversal" unit = Traversal #-}
{-# RULES "snocTraversal" snoc = snocTraversal #-}
-- | Efficiently avoid needlessly rebinding when using 'snoc' on an action that already returns ()
-- A rewrite rule automatically applies this when possible
snocTraversal :: Reducer (f ()) (Traversal f) => Traversal f -> f () -> Traversal f
snocTraversal a = mappend a . Traversal
-- | A 'WrappedApplicative' turns any 'Alternative' instance into a 'Monoid'.
-- It also provides a 'Multiplicative' instance for an 'Applicative' functor wrapped around a 'Monoid'
-- and asserts that any 'Alternative' applied to a 'Monoid' forms a 'LeftSemiNearRing'
-- under these operations.
newtype WrappedApplicative f a = WrappedApplicative { getWrappedApplicative :: f a }
deriving (Eq,Ord,Show,Read,Functor,Pointed,Applicative,Alternative,Copointed)
instance Alternative f => Monoid (WrappedApplicative f a) where
mempty = empty
WrappedApplicative a `mappend` WrappedApplicative b = WrappedApplicative (a <|> b)
instance (Alternative f, Monoid a) => Multiplicative (WrappedApplicative f a) where
one = pure mempty
times = liftA2 mappend
instance (Alternative f, c `Reducer` a) => Reducer c (WrappedApplicative f a) where
unit = WrappedApplicative . pure . unit
instance (Alternative f, Monoid a) => LeftSemiNearRing (WrappedApplicative f a)