packages feed

variadic-function (empty) → 0.1.0.0

raw patch · 8 files changed

+304/−0 lines, 8 filesdep +basedep +hspecdep +variadic-functionsetup-changed

Dependencies added: base, hspec, variadic-function

Files

+ ChangeLog.md view
@@ -0,0 +1,3 @@+# Changelog for variadic-function++## Unreleased changes
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright Boris Lykah (c) 2021++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 Boris Lykah 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, INDIRECT, 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,52 @@+# variadic-function++Create and transform functions with variable arity.++### How to use++The core of the library is the `Function` class. Use `createFunction` to make a function with a variable number of arguments. Use `transformFunction` to access the arguments and change the result of any function.+++```haskell+constN :: Function f args a EmptyConstraint+       => a -> f+constN a = createFunction+  -- The arguments are not constrained+  (undefined :: p EmptyConstraint)+  -- Combine argument with accumulator. Here we just ignore the argument+  const+  -- Ignore the accumulator and return `a` as a result+  (const a)+  -- Accumulator for combining with the arguments.+  -- We don't take any information from the arguments, so it is just ()+  ()++composeN :: (Function f args b EmptyConstraint, Function g args a EmptyConstraint)+         => (a -> b) -> g -> f+composeN f = transformFunction+  -- The arguments are not constrained+  (undefined :: p EmptyConstraint)+  -- Ignore arguments+  const+  -- Ignore the accumulator and apply f to result of the original function `g`+  (\_ r -> f r)+  -- Composition does not use the accumulator either, so it is ()+  ()++Here is a more complex example that constrains arguments and uses the accumulator:++```haskell+sumN :: forall r f args. (Function f args r ((~) r), Num r)+     => f+sumN = createFunction+  -- The argument must be the same type as the function result. +  -- To be able to mention `r` in here, the function signature +  -- has `forall` and ScopedTypeVariables is enabled.+  (undefined :: proxy ((~) r))+  -- Add argument to the accumulator+  (+)+  -- Return accumulator as the result+  id+  -- The initial value of accumulator+  0+```
+ Setup.hs view
@@ -0,0 +1,3 @@+import Distribution.Simple++main = defaultMain
+ src/Data/Function/Variadic.hs view
@@ -0,0 +1,91 @@+module Data.Function.Variadic+  ( -- * Decomposition and creation of functions+    Function (..),+    ConstructFunction,+    DeconstructFunction,++    -- * Helper classes for argument constraints+    EmptyConstraint,+    type (&),+  )+where++import Data.Kind (Type)++-- | Toolkit for creating and transforming functions with a variable number of arguments.+-- Its parameters are function, list of its arguments, its result, and `argC`+-- that constraints all arguments of the function.+class+  (ConstructFunction args r ~ f, DeconstructFunction f ~ '(args, r)) =>+  Function f args r argC+  where+  -- | Create a new function+  --+  -- === __Example usage__+  --+  -- >>> printf :: Function Show f args String => f+  -- >>> printf = createFunction (Proxy :: Proxy Show) (\acc a -> acc <> show a) id ""+  -- >>> printf "hello" () :: String+  -- "hello()"+  createFunction ::+    -- | Required for unambiguous choice of Function instance+    proxy argC ->+    -- | Combine arguments with accumulator+    (forall a. argC a => acc -> a -> acc) ->+    -- | Make result of the function+    (acc -> r) ->+    -- | Accumulator+    acc ->+    f++  -- | Create a function with the same arguments as given one but may have a different result.+  transformFunction ::+    -- | Required for unambiguous choice of the Function instance+    proxy argC ->+    -- | Combine arguments with accumulator+    (forall a. argC a => acc -> a -> acc) ->+    -- | Create result of the `f` function using accumulator and the result of the function to transform+    (acc -> r0 -> r) ->+    -- | Accumulator+    acc ->+    -- | The function to transform+    ConstructFunction args r0 ->+    -- | The new function+    f++-- | Extract list of arguments and the result from the function.+type family DeconstructFunction (f :: Type) :: ([Type], Type) where+  DeconstructFunction (a -> f) = MapFst ((:) a) (DeconstructFunction f)+  DeconstructFunction x = '( '[], x)++type family MapFst (f :: k1 -> k1) (tuple :: (k1, k2)) where+  MapFst f '(a, b) = '(f a, b)++-- | Given the types of function arguments and its result, make a type of a function.+type family ConstructFunction (args :: [Type]) (r :: Type) where+  ConstructFunction '[] r = r+  ConstructFunction (a : args) r = a -> ConstructFunction args r++instance+  ('( '[], r) ~ DeconstructFunction r) =>+  Function r '[] r argC+  where+  createFunction _ _ fr r = fr r+  transformFunction _ _ fr acc r = fr acc r++instance+  (Function f args r argC, argC a) =>+  Function (a -> f) (a : args) r argC+  where+  createFunction pArgC fa fr acc = createFunction pArgC fa fr . fa acc+  transformFunction pArgC fa fr acc f = \a -> transformFunction pArgC fa fr (fa acc a) (f a)++-- | When the arguments are not constrained, use this as the argC parameter of `Function`.+class EmptyConstraint a++instance EmptyConstraint a++-- | Combine constraints. For example, @Function f args x (Show & Num)@.+class (f x, g x) => (&) f g (x :: k)++instance (f x, g x) => (&) f g x
+ src/Data/Function/Variadic/Utils.hs view
@@ -0,0 +1,33 @@+module Data.Function.Variadic.Utils+  ( composeN,+    constN,+    mappendN,+  )+where++import Data.Function.Variadic++-- | Function composition for an arbitrary number of arguments.+--+-- >>> (show `composeN` \a b c -> (a + b + c :: Int)) 1 2 3+-- "6"+composeN :: (Function f args b EmptyConstraint, Function g args a EmptyConstraint) => (a -> b) -> g -> f+composeN f = transformFunction (undefined :: p EmptyConstraint) const (\_ r -> f r) ()++-- | Constant function for an arbitrary number of arguments.+--+-- @+-- let const2 = constN :: x -> a -> b -> x+-- @+--+-- >>> zipWith3 (constN 1) [1..10] [1..5] ["a", "b", "c"] :: [Int]+-- [1,1,1]+constN :: Function f args a EmptyConstraint => a -> f+constN a = createFunction (undefined :: p EmptyConstraint) const (const a) ()++-- | Append multiple monoid values. It is similar to `mconcat` but takes the values as arguments rather than list elements.+--+-- >>> mappendN [1, 2] [3] [4, 5] :: [Int]+-- [1,2,3,4,5]+mappendN :: forall r f args. (Function f args r ((~) r), Monoid r) => f+mappendN = createFunction (undefined :: proxy ((~) r)) mappend id mempty
+ test/Spec.hs view
@@ -0,0 +1,16 @@+{-# LANGUAGE TypeApplications #-}++import Data.Function.Variadic+import Data.Function.Variadic.Utils+import Test.Hspec++main :: IO ()+main = hspec $ do+  describe "Variadic function" $ do+    it "transforms function" $ do+      let f :: Int -> Int -> Int -> String+          f = show `composeN` \a b c -> a + b + c+      f 1 2 3 `shouldBe` "6"+    it "transforms function with inferred type" $ do+      let f = show `composeN` \a b c -> (a + b + c :: Int)+      f 1 2 3 `shouldBe` "6"
+ variadic-function.cabal view
@@ -0,0 +1,76 @@+cabal-version: 1.12++-- This file has been generated from package.yaml by hpack version 0.34.4.+--+-- see: https://github.com/sol/hpack++name:           variadic-function+version:        0.1.0.0+synopsis:       Create and transform functions with variable arity.+description:    Please see the README on GitHub at <https://github.com/lykahb/variadic-function#readme>+category:       Data, Functions+homepage:       https://github.com/lykahb/variadic-function#readme+bug-reports:    https://github.com/lykahb/variadic-function/issues+author:         Boris Lykah+maintainer:     lykahb@gmail.com+copyright:      2021 Boris Lykah+license:        BSD3+license-file:   LICENSE+build-type:     Simple+extra-source-files:+    README.md+    ChangeLog.md++source-repository head+  type: git+  location: https://github.com/lykahb/variadic-function++library+  exposed-modules:+      Data.Function.Variadic+      Data.Function.Variadic.Utils+  other-modules:+      Paths_variadic_function+  hs-source-dirs:+      src+  default-extensions:+      ConstraintKinds+      DataKinds+      FlexibleContexts+      FlexibleInstances+      MultiParamTypeClasses+      PolyKinds+      RankNTypes+      TypeFamilies+      TypeOperators+      UndecidableInstances+      UndecidableSuperClasses+  build-depends:+      base >=4.7 && <5+  default-language: Haskell2010++test-suite variadic-function-test+  type: exitcode-stdio-1.0+  main-is: Spec.hs+  other-modules:+      Paths_variadic_function+  hs-source-dirs:+      test+  default-extensions:+      ConstraintKinds+      DataKinds+      FlexibleContexts+      FlexibleInstances+      MultiParamTypeClasses+      PolyKinds+      RankNTypes+      TypeFamilies+      TypeOperators+      UndecidableInstances+      UndecidableSuperClasses+  ghc-options: -threaded -rtsopts -with-rtsopts=-N+  build-depends:+      base >=4.7 && <5+    , hspec+    , variadic-function+  default-language: Haskell2010