formatting-3.0.0: src/Formatting/Holey.hs
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE OverloadedStrings #-}
{-# OPTIONS -Wall #-}
-- |
-- Module : Formatting.Holey
-- Copyright : (c) 2013 Chris Done, 2013 Shachaf Ben-Kiki
-- License : BSD3
-- Maintainer : chrisdone@gmail.com
-- Stability : experimental
-- Portability : GHC
--
-- Copy of the holey monoids library but with constructor exported.
module Formatting.Holey
(
-- * Formatting library
Format,
Holey (..),
(%),
now,
bind,
later,
hmap
) where
import Data.Monoid
import Data.String
import Data.Text.Lazy.Builder (Builder)
-- | A formatter.
type Format a = forall r. Holey Builder r (a -> r)
-- | The type of a monoid with holes. The underlying monoid is
-- represented by type parameter @m@. The @r@ is the result type and
-- stays polymorphic until the very last moment when 'run' is
-- called. The last argument @a@ is always a function with zero or
-- more arguments, finally resulting in @r@. Ordering the arguments in
-- this order allows holey monoids to be composed using `.`, stacking
-- the expected arguments. Note that the `Monoid` constraint is only
-- used in the identity 'Holey' and in composing two 'Holey's.
newtype Holey m r a = Holey { runHM :: (m -> r) -> a }
-- | Very useful instance for writing format string.
instance (IsString m, a ~ r) => IsString (Holey m r a) where
fromString = now . fromString
-- | Composition operator. The same as category composition.
(%) :: Monoid n => Holey n b c -> Holey n b1 b -> Holey n b1 c
f % g = f `bind` \a -> g `bind` \b -> now (a `mappend` b)
-- | Insert a constant monoidal value.
now :: m -> Holey m r r
now a = Holey ($ a)
-- | Monadic indexed bind for holey monoids.
bind :: Holey m b c -> (m -> Holey n a b) -> Holey n a c
m `bind` f = Holey $ \k -> runHM m (\a -> runHM (f a) k)
-- | Insert a monoidal value that is not specified until the
-- computation is 'run'. The argument that is expected later is
-- converted to the monoid type using the given conversion function.
later :: (a -> m) -> Holey m r (a -> r)
later f = Holey (. f)
-- | Convert between underlying 'Monoid' types.
hmap :: (m -> n) -> Holey m r a -> Holey n r a
hmap g m = Holey (\k -> runHM m (k . g))