packages feed

function-builder (empty) → 0.1.0.0

raw patch · 8 files changed

+453/−0 lines, 8 filesdep +basesetup-changed

Dependencies added: base

Files

+ .travis.yml view
@@ -0,0 +1,30 @@+language: c++sudo: false++addons:+  apt:+    sources:+    - hvr-ghc+    packages:+    - ghc-8.6.3++before_install:+ - mkdir -p ~/.local/bin+ - travis_retry curl -L https://www.stackage.org/stack/linux-x86_64 | tar xz --wildcards --strip-components=1 -C ~/.local/bin '*/stack'+ - export PATH=~/.local/bin:/opt/ghc/$GHCVER/bin:$PATH+ - chmod a+x ~/.local/bin/stack++install:+  - stack --no-terminal --skip-ghc-check setup++script:+  - stack --no-terminal --skip-ghc-check build+  - stack --no-terminal --skip-ghc-check haddock++cache:+  directories:+  - ~/.stack+  - ~/.local+  - ~/.stack-work-cache+  apt: true
+ CHANGELOG.md view
@@ -0,0 +1,3 @@+# 0.1.0.0++* Initial Release
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright Sven Heyll (c) 2019++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of Author name here nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, addParameter, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,45 @@+[![Build Status](https://travis-ci.org/sheyll/function-builder.svg?branch=master)](https://travis-ci.org/sheyll/function-builder)++[![Hackage](https://img.shields.io/hackage/v/function-builder.svg?style=flat)](http://hackage.haskell.org/package/function-builder)++# A library for making Monoid writing functions with variable number of parameters++**Also known as: Holey monoids.**++This library is made to be useful especially for library authors, who want to provide users+with building blocks to create functions that compose a monoidal structure+from their parameters in a type safe way. Think of `printf`.++Imagine a library that let`s user create nicely formatted strings, with the ability to+compose strings into larger strings and to allow the rendering of+all sorts of values, for example `Double`s, `Bool`s, or lists to strings.++**This library** allows the author of such a library to easily add the+building blocks, allowing users to build **poly variadic functions**, i.e. with parameters+depending on the order and composition of these building blocks.++Several `FunctionBuilder` values sharing a common monoidal output type can be composed+to a big `FunctionBuilder` value, in order to build an **output function** that+has a flexible number and types of parameters depending, on the individual+`FunctionBuilder`s used. This output function can be obtained by `toFunction`.++`FunctionBuilder`s can also be composed via standard type classes.++This module gives you ready-made  like `Functor`, `Applicative`, `Semigroup`, `Monoid` or Category` instances;++The basic building blocks are `toFunction`, `immediate` and `addParameter`.++For example, you could use this library to build a string formatting+library, that allows users to compose arbitrary, _printf-style_ render **functions**+from reusable building blocks, such that they can be re-combined in order to make+get functions, that can be applied to parameters that fill place holders, like e.g.:++     renderCpuTemp :: Int -> Float -> String+     renderCpuTemp =+       toFunction (render "CPU " . renderInt . render " Temperature: " . renderFloat)++## Similar Libraries++* [polyToMonoid](http://hackage.haskell.org/package/polyToMonoid)++* [HoleyMonoid](http://hackage.haskell.org/package/HoleyMonoid)
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ function-builder.cabal view
@@ -0,0 +1,54 @@+name:                function-builder+version:             0.1.0.0+synopsis:            Create poly variadic functions for monoidal results+description:         Please see README.md+homepage:            https://github.com/sheyll/function-builder#readme+license:             BSD3+license-file:        LICENSE+author:              Sven Heyll+maintainer:          sven.heyll@gmail.com+copyright:           2019 Sven Heyll+category:            Data Structures+build-type:          Simple+extra-source-files:   README.md+                    , CHANGELOG.md+                    , stack.yaml+                    , .travis.yml+cabal-version:       >=1.10++library+  hs-source-dirs:      src+  exposed-modules:     Data.FunctionBuilder+  build-depends:       base >= 4.11 && < 5+  default-language:    Haskell2010+  default-extensions:  BangPatterns+                     , ConstraintKinds+                     , DataKinds+                     , DefaultSignatures+                     , DeriveDataTypeable+                     , DeriveFunctor+                     , DeriveGeneric+                     , DuplicateRecordFields+                     , FlexibleInstances+                     , FlexibleContexts+                     , FunctionalDependencies+                     , GADTs+                     , GeneralizedNewtypeDeriving+                     , KindSignatures+                     , MultiParamTypeClasses+                     , OverloadedStrings+                     , QuasiQuotes+                     , RecordWildCards+                     , RankNTypes+                     , ScopedTypeVariables+                     , StandaloneDeriving+                     , TupleSections+                     , TypeApplications+                     , TypeFamilies+                     , TypeInType+                     , TypeOperators+                     , TypeSynonymInstances++source-repository head+  type:     git+  location: https://github.com/sheyll/function-builder
+ src/Data/FunctionBuilder.hs view
@@ -0,0 +1,279 @@+-- | This library allows you to build function builder libraries.+--+-- This library is made to be useful especially for library authors, who want to provide+-- building blocks for users to build functions of varying parameters in a type safe way.+--+-- Imagine a library that let's user create nicely formatted strings, with the ability to+-- compose strings into larger strings and to allow the rendering of+-- all sorts of values, for example 'Double's, 'Bool's, or lists to strings.+--+-- __This library__ allows the author of such a library to easily add the+-- building blocks, allowing users to build __poly variadic functions__, i.e. with parameters+-- depending on the order and composition of these building blocks.+--+-- Several 'FunctionBuilder' values sharing a common monoidal output type can be composed+-- to a big 'FunctionBuilder' value, in order to build an __output function__ that+-- has a flexible number and types of parameters depending, on the individual+-- 'FunctionBuilder's used. This output function can be obtained by 'toFunction'.+--+-- 'FunctionBuilder's can also be composed via standard type classes.+--+-- This module gives you ready-made  like 'Functor', 'Applicative', 'Semigroup', 'Monoid' or 'Category' instances;+--+-- The basic building blocks are 'toFunction', 'immediate' and 'addParameter'.+--+-- For example, you could use this library to build a string formatting+-- library, that allows users to compose arbitrary, /printf-style/ render __/functions/__+-- from reusable building blocks, such that they can be re-combined in order to make+-- get functions, that can be applied to parameters that fill place holders, like e.g.:+--+-- @+--     renderCpuTemp :: Int -> Float -> String+--     renderCpuTemp =+--       toFunction (render "CPU " . renderInt . render " Temperature: " . renderFloat)+-- @+--+module Data.FunctionBuilder where++import           Control.Category+import           Data.Monoid+import           Data.Semigroup+import           Prelude                 hiding ( id+                                                , (.)+                                                )+import           Data.Tagged++-- | A function, that takes an accumulation function as paramater,+-- and returns a function that will have zero or more parameters and returns+-- an accumulated result: @(acc -> next)+--+-- A @FunctionBuilder acc next f@ is a function @(acc -> next) -> f@.+--+-- Type parameter:+--+-- [@acc@] The final output value that gets build up by the+-- applying the resulting function build by the composed @FunctionBuilder@s.+-- If you were building a @printf@ style library, then @acc@ would+-- probably be 'String'.+--+-- [@next@] The @next@ parameter allows composing @FunctionBuilder@s, and the final output+-- will be a function @f@ with zero or more parameters of different type+-- resulting in an @acc@ value. Most 'FunctionBuilder's are parameteric in @next@ and+-- also have @next@ in a in @f_make_next@.+-- Also note that in @(acc -> next) -> f_make_next@ the @next@ is+-- the output of the continuation @acc -> next@ passed to the @FunctionBuilder@ function,+-- hence this /output/ is actually in /input/ from the perspective of the @FunctionBuilder@,+-- which makes a @FunctionBuilder@ 'Contravariant' in @next@.+--+-- [@f_make_next@] This is usually a function that returns @next@ or is+-- directly @next@, this is the resulting - seemingly /poly variadic/ -+-- __outout function__ composed through the composition of @FunctionBuilder@s, and+-- obtained by 'toFunction'.+--+-- It is required for the type-class instances allowing the+-- composition as 'Semigroup's or 'Monoid's or even 'Category'.+--+-- It is totaly valid to apply it to 'id', to get @f@, and behind @f@+-- typically lies a function of some parameters to @next@.+--+-- At the end of /the chain/ @next@ will be @acc@ and before that+-- the function that takes the next parameters and then returns out.+--+-- See `toFunction`.+--+-- Composition comes in two flavours:+--+--     (1) By using `(.)` to add to the accumulator a value passed to an additional argument+--     of the resulting output function.+--+--     (2) By using `(<>)` to append a fixed value to the accumulator directly.+--+-- For example:+--+-- > import Data.Monoid (Sum(..))+-- >+-- > add :: FunctionBuilder (Sum Int) next (Int -> next)+-- > add = FB $ \k -> \x -> k (Sum x)+--+-- Here the @next@ parameter in @add@ is just passed through and+-- is the __key__ to be able to __compose__ @FunctionBuilder@s. @add@ is+-- parametric in @next@.+-- .+-- And when we are done composing, we pass `id` to the @FunctionBuilder@, which+-- forces the the @next@ parameter to match the @acc@ type, and which+-- would the make @add@ function look like this:+--+-- > addToZero :: FunctionBuilder (Sum Int) (Sum Int) (Int -> Sum Int)+-- > addToZero = add+newtype FunctionBuilder acc next f_make_next = FB {runFunctionBuilder :: (acc -> next) -> f_make_next }++-- | Compose 'FunctionBuilder's such that the output function first takes all parameters+-- from the first 'FunctionBuilder' and then all parameters from the second 'FunctionBuilder' and then+-- appends the results of both functions, which is why we need the 'Monoid' constraint.+instance Monoid m => Category (FunctionBuilder m) where+  (.) (FB f) (FB g) = FB (\k -> (f (\m1 -> g (\m2 -> k (m1 <> m2)))))+  id = FB ($ mempty)++-- | Allow appending a 'FunctionBuilder' to another without changing the resulting output function.+-- For example, 'FunctionBuilder's that have @FunctionBuilder m r r@ can append something to @m@.+-- It is not possible to add new parameters to the output function, this can only be done by+-- the 'Category' instance.+instance Semigroup m => Semigroup (FunctionBuilder m r r) where+  (<>) (FB f) (FB g) = FB (\k -> (f (\m1 -> g (\m2 -> k (m1 <> m2)))))++-- | Allow appending a 'FunctionBuilder' to another without changing the resulting output function.+-- For example, 'FunctionBuilder's that have @FunctionBuilder m r r@ can append something to @m@.+-- It is not possible to add new parameters to the output function, this can only be done by+-- the 'Category' instance.+instance Monoid m => Monoid (FunctionBuilder m r r) where+  mappend = (<>)+  mempty  = id++instance Functor (FunctionBuilder m r) where+  fmap f (FB !h) = FB $ \k -> f (h k)++instance Applicative (FunctionBuilder m r) where+  pure = FB . const+  (FB f) <*> (FB x) = FB (\k -> f k (x k))++instance Monad (FunctionBuilder m r) where+  (FB m) >>= f = FB (\k -> runFunctionBuilder (f (m k)) k)++-- | Turn a 'FunctionBuilder' into the __output function__ that consumes+-- zero or more of parameter and then always return @outout@.+--+-- If passed a 'FunctionBuilder' value of type @FunctionBuilder String String (Int -> Double -> Int -> String)@+--+-- For example:+--+-- > 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+toFunction = ($ id) . runFunctionBuilder++-- ** Building 'FunctionBuilder's++-- | 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)+--+-- 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+immediate m = FB { runFunctionBuilder = ($ m) }++-- | Create a 'FunctionBuilder' that adds an argument to the output function,+-- and converts that argument to a value that can be accumulated in the+-- resulting monoidal value.+--+-- This is a smart constructor for a 'FunctionBuilder'.+-- This functions is probably equal to:+--+-- > addParameter f = FB (\k x -> k (f x))+--+-- 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 = addParameter show+--+-- > example :: (Show a, Show b) => a -> b -> String+-- > example = toFunction (showing . showing)+--+-- >>> example True 0.33214+-- "True0.33214"+--+-- See the example in `toFunction`.+addParameter :: (a -> m) -> FunctionBuilder m r (a -> r)+addParameter f = FB { runFunctionBuilder = (. f) }++-- ** Modifying Parameters of 'FunctionBuilder's++-- | Take away a function parameter added with 'addParameter' by /pre -/ applying it to some+-- value.+-- This is equivalent to:+--+-- @+--     fillParameter f x = f <*> pure x+-- @+--+fillParameter :: FunctionBuilder m r (a -> b) -> a -> FunctionBuilder m r b+fillParameter (FB !f) x = FB $ \k -> f k x++-- | 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)+tagParameter = fmap (\f -> f . untag)++-- ** 'FunctionBuilder' Transformations++-- | Compose to 'FunctionBuilder's such that the second 'FunctionBuilder' may depend on the intermediate result+-- of the first. If you skwirm hard enough you __almost__ see '(>>=)' with @m ~ n@.+bind+  :: FunctionBuilder m b c+  -> (m -> FunctionBuilder n a b)+  -> FunctionBuilder n a c+bind mbc fm =+  FB $ \kna -> runFunctionBuilder mbc (($ kna) . runFunctionBuilder . fm)++-- | 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+mapAccumulator into (FB f) = FB (\k -> f (k . into))++-- | Convert the output of a 'FunctionBuilder' value; since most+-- 'FunctionBuilder's 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+mapNext outof (FB f) = FB (\k -> f (outof . k))
+ stack.yaml view
@@ -0,0 +1,10 @@+resolver: lts-13.3++packages:+- '.'++extra-deps: []++flags: {}++extra-package-dbs: []