-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Create poly variadic functions for monoidal results -- -- Please see README.md @package function-builder @version 0.3.0.0 -- | A builder for functions of variable parameters -- -- FunctionBuilder values can be composed, and eventually -- rendered into a function by toFunction. -- -- For example the composition of: -- --
-- fb1 :: FunctionBuilder MyMonoid composeMe (Int -> composeMe) -- fb1 = deferred ... -- -- fb2 :: FunctionBuilder MyMonoid composeMe (String -> composeMe) -- fb2 = deferred ... -- -- fb3 :: FunctionBuilder MyMonoid composeMe (Bool -> composeMe) -- fb3 = deferred ... -- -- fb :: FunctionBuilder MyMonoid composeMe (Int -> String -> Bool -> composeMe) -- fb = fb1 . fb2 . fb3 -- -- f :: Int -> String -> Bool -> MyMonoid -- f = toFunction fb123 ---- -- FunctionBuilders are composed via . from Category -- and <> from Semigroup. -- -- This module provides Functor, Applicative, Monad, -- Semigroup, Monoid and Category instances; -- -- The smart-constructors immediate and deferred create -- FunctionBuilders that either write a hard coded constant to the -- output Monoid or add a function that will be applied to an -- additional runtime parameter. -- -- Further glue-code is provided to allow changing the underlying -- Monoid, see bind. module Data.FunctionBuilder -- | A tricky newtype wrapper around a function that carries out a -- computation resulting in a monoidal output value that is passed to a -- continuation. -- -- Type parameters: -- --
-- fb1 :: FunctionBuilder MyMonoid next (Int -> next) -- fb1 = deferred undefined -- -- fb2 :: FunctionBuilder MyMonoid next (String -> next) -- fb2 = deferred undefined -- -- newtype MyMonoid = MyMonoid () deriving (Semigroup, Monoid) ---- -- When we desugar with ghci: -- --
-- >>> :t (runFunctionBuilder fb1) -- (runFunctionBuilder fb1) :: (MyMonoid -> next) -> Int -> next ---- --
-- >>> :t (runFunctionBuilder fb2) -- (runFunctionBuilder fb2) :: (MyMonoid -> next) -> String -> next ---- -- Composition comes in two flavours: -- --
-- >>> :t (fb1 . fb2) -- (fb1 . fb2) :: FunctionBuilder MyMonoid a (Int -> String -> a) ---- -- And desugared: -- --
-- >>> :t runFunctionBuilder (fb1 . fb2) -- runFunctionBuilder (fb1 . fb2) :: (MyMonoid -> next) -> Int -> String -> next ---- -- What happened during composition was that the next in -- fb1 was used to insert into Int -> next the -- String -> other_next from fb2; such that this -- results in Int -> (String -> other_next). (Note: For -- clarity I renamed the type local type parameter next to -- other_next from fb2) -- -- Also, there is the StaticContent type class for types that have -- function builders. -- -- NOTE: FunctionBuilder w a b is actually Cokleisli -- ((->) w) a b When w is a Monoid then, -- ((->) w) is a Comonad instance. The reason why -- this library does not use the comonad library under the hood is -- currently only the missing Semigroup and Monoid -- instances; and to avoid orphan instances a newtype wrapper would be -- required, and that does not justify the additional dependency and the -- pollution of this library with scary Cokleislies and -- Comonads. newtype FunctionBuilder acc next f_make_next FB :: ((acc -> next) -> f_make_next) -> FunctionBuilder acc next f_make_next [$sel:runFunctionBuilder:FB] :: FunctionBuilder acc next f_make_next -> (acc -> next) -> f_make_next -- | Get the composed output function of a FunctionBuilder. -- -- The FunctionBuilder passed to this function must match this -- signature: -- --
-- FunctionBuilder m m (arg0 -> .. -> m) ---- -- This means that the result of the generated function arg0 -> .. -- -> m MUST be m, the underlying Monoid. -- -- The FunctionBuilders generated by deferred and -- immediate are parametric in the second type parameter and match -- the type signature required by this function. -- -- Example 1: -- --
-- fb :: FunctionBuilder String String (Int -> Double -> Int -> String) -- fb = undefined -- -- example :: Int -> Double -> Int -> String -- example = toFunction fb ---- -- Example 2: -- --
-- example :: Int -> Double -> Int -> String -- example = toFunction (i . d . i) -- -- s :: String -> FunctionBuilder String a a -- s x = FB (\k -> k x) -- -- i :: FunctionBuilder String next (Int -> next) -- i = FB (\k x -> k $ show x) -- -- d :: FunctionBuilder String next (Double -> next) -- d = FB (\k x -> k $ show x) --toFunction :: FunctionBuilder output output make_output -> make_output -- | A smart constructor for a FunctionBuilder with that will build -- a function with a parameter, and when the generated function is -- applied at that parameter the function given here will be applied to -- the argument and the resulting monoidal value will be appended to the -- result. -- -- The generated builder can be passed to toFunction since it is -- parametric in its second type parameter. -- -- Example: -- -- When building a String formatting FunctionBuilder the -- function to append a parameter that has a show instance could be: -- --
-- showing :: Show a => FunctionBuilder String r (a -> r) -- showing = deferred show ---- --
-- example :: (Show a, Show b) => a -> b -> String -- example = toFunction (showing . showing) ---- --
-- >>> example True 0.33214 -- "True0.33214" ---- -- See the example in toFunction. deferred :: (a -> m) -> FunctionBuilder m r (a -> r) -- | Create a FunctionBuilder that appends something to the -- (monoidal-) output value. -- -- This is a smart constructor for a FunctionBuilder. This -- functions is probably equal to: -- --
-- immediate x = FB (\k -> k x) ---- -- The generated builder can be passed to toFunction since it is -- parametric in its second type parameter. -- -- Example: -- -- When building a String formatting FunctionBuilder the -- function to append a literal string could be: -- --
-- s :: String -> FunctionBuilder String a a -- s = immediate ---- --
-- c :: Char -> FunctionBuilder String a a -- c = immediate . (:[]) ---- --
-- example :: String -- example = toFunction (s "hello" . c ' ' . s "world") ---- --
-- >>> example -- "hello world" ---- -- See the example in toFunction. immediate :: m -> FunctionBuilder m r r -- | Types a that can be turned into FunctionBuilders for a -- base monoid m. -- -- This is the abstract version of StaticContent and -- DynamicContent class HasFunctionBuilder m a where { -- | Get the function type (if any) of the builder. type family ToFunction m a r; type ToFunction m a r = r; } -- | Make a FunctionBuilder from some value. toFunctionBuilder :: HasFunctionBuilder m a => a -> FunctionBuilder m r (ToFunction m a r) -- | Types a that can be turned into FunctionBuilders for a -- base monoid m. -- -- These type can provide a function to work on the internal monoid, -- -- They can be constructed using immediate. -- -- Of course they can incorporate information statically known at -- compile time or via type class dictionaries (through singletons -- for instance). -- -- For example: -- --
-- instance forall s . (KnownSymbol s) => StaticContent String (Proxy s) where -- addStaticContent = immediate (symbolVal (Proxy @s)) --class StaticContent m a -- | Return a FunctionBuilder that can work on the underlying -- monoid. addStaticContent :: StaticContent m a => a -> FunctionBuilder m next next -- | Return a FunctionBuilder that can work on the underlying -- monoid. addStaticContent :: (StaticContent m a, a ~ m) => a -> FunctionBuilder m next next -- | Types that have a FunctionBuilder with a runtime -- parameter for a base monoid m. -- -- For example: If an instance adds an Int parameter, it will -- define this family instance: -- --
-- instance DynamicContent String (Proxy "%i") Int where -- addParameter _ = deferred --class DynamicContent m a parameter | m a -> parameter -- | Create a FunctionBuilder that adds a parameter to the output -- function, and converts that argument to a value that can be -- accumulated in the resulting monoidal value. addParameter :: DynamicContent m a parameter => a -> FunctionBuilder m next (parameter -> next) -- | Create a FunctionBuilder that adds a parameter to the output -- function, and converts that argument to a value that can be -- accumulated in the resulting monoidal value. addParameter :: (DynamicContent m a parameter, a ~ (parameter -> m)) => a -> FunctionBuilder m next (parameter -> next) -- | Take away a function parameter added with addParameter by -- pre - applying it to some value. -- -- For example: -- --
-- intArg :: FunctionBuilder MyMonoid a (Int -> a) -- intArg = deferred undefined -- -- stringArg :: FunctionBuilder MyMonoid a (String -> a) -- stringArg = deferred undefined -- -- twoInt :: FunctionBuilder MyMonoid a (Int -> String -> a) -- twoInt = intArg . stringArg -- -- example :: FunctionBuilder MyMonoid a (String -> a) -- example = fillParameter twoInt 42 ---- -- This is equivalent to: -- --
-- fillParameter f x = f * pure x --fillParameter :: FunctionBuilder m r (a -> b) -> a -> FunctionBuilder m r b -- | Convert a FunctionBuilder for a function (a -> b) -- to (Tagged tag a -> b). tagParameter :: forall tag m r a b. FunctionBuilder m r (a -> b) -> FunctionBuilder m r (Tagged tag a -> b) -- | Compose to FunctionBuilders such that the second -- FunctionBuilder may depend on the intermediate result of the -- first. Similar to a monadic bind >>= but more flexible -- sind the underlying Monoid may change too, for example: -- --
-- intText :: FunctionBuilder Text next (Int -> next) -- intText = deferred undefined -- -- unpackB :: Text -> FunctionBuilder String next next -- unpackB = immediate . unpack -- -- intStr :: FunctionBuilder String next (Int -> next) -- intStr = intText `bind` unpackB --bind :: FunctionBuilder m g_next f_g_next -> (m -> FunctionBuilder n next g_next) -> FunctionBuilder n next f_g_next -- | Convert the accumulated (usually monoidal-) value, this allows to -- change the underlying accumlator type. mapAccumulator :: (m -> n) -> FunctionBuilder m a b -> FunctionBuilder n a b -- | Convert the output of a FunctionBuilder value; since most -- FunctionBuilders are parameteric in r they also have -- r in a in a, such that a always either is -- r or is a function returning r eventually. -- -- In order to get from a FunctionBuilder that can accept a -- continuation returning it an r to a FunctionBuilder -- that accepts continuations returning an s instead, we need to -- apply a function s -> r to the return value of the -- continuation. -- -- Note that a mapNext will not only change the r to an -- s but probably also the the a, when it is -- parametric, as in this contrived example: -- --
-- example :: Int -> x -> Sum Int -- example = toFunction (ign add) -- -- add :: FunctionBuilder (Sum Int) next (Int -> next) -- add = FB (\k x -> k $ Sum x) -- -- ign :: FunctionBuilder m (x -> r) a -> FunctionBuilder m r a -- ign = mapNext const ---- -- Here the extra parameter x is pushed down into the -- a of the add FunctionBuilder. mapNext :: (s -> r) -> FunctionBuilder m r a -> FunctionBuilder m s a instance GHC.Base.Monoid m => Control.Category.Category (Data.FunctionBuilder.FunctionBuilder m) instance GHC.Base.Semigroup m => GHC.Base.Semigroup (Data.FunctionBuilder.FunctionBuilder m r r) instance GHC.Base.Monoid m => GHC.Base.Monoid (Data.FunctionBuilder.FunctionBuilder m r r) instance GHC.Base.Functor (Data.FunctionBuilder.FunctionBuilder m r) instance GHC.Base.Applicative (Data.FunctionBuilder.FunctionBuilder m r) instance GHC.Base.Monad (Data.FunctionBuilder.FunctionBuilder m r)