{-# LANGUAGE CPP #-} {-# LANGUAGE RankNTypes #-} ----------------------------------------------------------------------------- -- | -- Module : Control.Alternative.Free.Final -- Copyright : (C) 2012 Edward Kmett -- License : BSD-style (see the file LICENSE) -- -- Maintainer : Edward Kmett -- Stability : provisional -- Portability : GADTs, Rank2Types -- -- Final encoding of free 'Alternative' functors. ---------------------------------------------------------------------------- module Control.Alternative.Free.Final ( Alt(..) , runAlt , liftAlt , hoistAlt ) where import Control.Applicative import Data.Functor.Apply import Data.Functor.Alt (()) import qualified Data.Functor.Alt as Alt #if !(MIN_VERSION_base(4,11,0)) import Data.Semigroup #endif -- | The free 'Alternative' for any @f@. newtype Alt f a = Alt { _runAlt :: forall g. Alternative g => (forall x. f x -> g x) -> g a } instance Functor (Alt f) where fmap f (Alt g) = Alt (\k -> fmap f (g k)) instance Apply (Alt f) where Alt f <.> Alt x = Alt (\k -> f k <*> x k) instance Applicative (Alt f) where pure x = Alt (\_ -> pure x) Alt f <*> Alt x = Alt (\k -> f k <*> x k) instance Alt.Alt (Alt f) where Alt x Alt y = Alt (\k -> x k <|> y k) instance Alternative (Alt f) where empty = Alt (\_ -> empty) Alt x <|> Alt y = Alt (\k -> x k <|> y k) some (Alt x) = Alt $ \k -> some (x k) many (Alt x) = Alt $ \k -> many (x k) instance Semigroup (Alt f a) where (<>) = (<|>) instance Monoid (Alt f a) where mempty = empty mappend = (<>) -- | A version of 'lift' that can be used with @f@. liftAlt :: f a -> Alt f a liftAlt f = Alt (\k -> k f) -- | Given a natural transformation from @f@ to @g@, this gives a canonical monoidal natural transformation from @'Alt' f@ to @g@. runAlt :: forall f g a. Alternative g => (forall x. f x -> g x) -> Alt f a -> g a runAlt phi g = _runAlt g phi -- | Given a natural transformation from @f@ to @g@ this gives a monoidal natural transformation from @Alt f@ to @Alt g@. hoistAlt :: (forall a. f a -> g a) -> Alt f b -> Alt g b hoistAlt phi (Alt g) = Alt (\k -> g (k . phi))