polyvariadic (empty) → 0.3.0.0
raw patch · 6 files changed
+241/−0 lines, 6 filesdep +basedep +containersdep +semigroupssetup-changed
Dependencies added: base, containers, semigroups
Files
- ChangeLog.md +6/−0
- Data/Accumulator.hs +59/−0
- Data/Function/Polyvariadic.hs +110/−0
- LICENSE +30/−0
- Setup.hs +2/−0
- polyvariadic.cabal +34/−0
+ ChangeLog.md view
@@ -0,0 +1,6 @@+# Revision history for polyvariadic++## 0.3.0.0 -- 2017-04-19++* First public version.+
+ Data/Accumulator.hs view
@@ -0,0 +1,59 @@+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE CPP #-}++-- |+-- Module : Data.Accumulator+-- Copyright : (c) Francesco Gazzetta 2017+-- License : BSD3 (see the file LICENSE)+--+-- Maintainer : francygazz@gmail.org+-- Stability : stable+-- Portability : portable+--+-- Accumulators, primarily useful for Polyvariadic++module Data.Accumulator+ ( Accumulator (..)+ , singleton+ , accumulateMany+ , AccumulatorSemigroup (..)+ ) where++import qualified Data.Set as Set+import Data.Foldable (foldl')+import Data.Semigroup++#if !MIN_VERSION_base(4,8,0)+import Data.Foldable+#endif++-- | An 'Accumulator c i' supports accumulation of elements of type i in it.+-- This is different from 'Semigroup' or 'Monoid', where '<>' acts between+-- two values with the same type.+class Accumulator acc x where+ accumulate :: x -> acc -> acc -- ^ Accumulate a value++-- | Accumulate a single value in a 'Monoid'+singleton :: (Accumulator acc x, Monoid acc) => x -> acc+singleton = flip accumulate mempty++-- | Strictly accumulate multiple values from a 'Foldable', from left to right+accumulateMany :: (Foldable f, Accumulator acc x) => f x -> acc -> acc+accumulateMany xs acc = foldl' (flip accumulate) acc xs++instance Accumulator [a] a where+ accumulate = (:)++instance Ord a => Accumulator (Set.Set a) a where+ accumulate = Set.insert++instance Semigroup m => Accumulator (AccumulatorSemigroup m) (AccumulatorSemigroup m) where+ accumulate = (<>)++-- | Lift a 'Semigroup' into an Accumulator. This is a newtype because (<>) isn't always the ideal way of accumulating+newtype AccumulatorSemigroup a = AccumulatorSemigroup {getAccumulatorSemigroup :: a}++instance Semigroup m => Semigroup (AccumulatorSemigroup m) where+ (<>) (AccumulatorSemigroup a) (AccumulatorSemigroup b) = AccumulatorSemigroup $ (<>) a b+
+ Data/Function/Polyvariadic.hs view
@@ -0,0 +1,110 @@+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE FlexibleInstances #-}++-- |+-- Module : Data.Function.Polyvariadic+-- Copyright : (c) Francesco Gazzetta 2017+-- License : BSD3 (see the file LICENSE)+--+-- Maintainer : francygazz@gmail.org+-- Stability : experimental+-- Portability : portable+--+-- Create and apply functions with an arbitrary number of arguments.++module Data.Function.Polyvariadic+ ( -- * Creation+ Polyvariadic (..)+ -- * Application+ , Apply (apply')+ , apply+ ) where++import Data.Foldable+import Data.Accumulator+++---- creation++-- | Creation of functions with an arbitrary number of arguments.+--+-- The arguments will be accumulated in the given 'Accumulator',+-- which will then be passed as an argument to the function.+--+-- ==== __Examples__+--+-- Three integers to a list. Note that you have to add type annotations+-- for nearly everything to avoid ambiguities+-- >>> polyvariadic mempty (id :: [Int] -> [Int]) (1::Int) (2::Int) (3::Int) :: [Int]+--+-- The classic @printf@ function, which takes an arbitrary amount of arguments+-- and inserts them in a string:+--+-- @+-- {-# LANGUAGE MultiParamTypeClasses #-}+-- {-# LANGUAGE FlexibleInstances #-}+-- {-# LANGUAGE FlexibleContexts #-}+-- import Data.Function.Polyvariadic+-- import Data.Accumulator+--+-- magicChar = \'%\'+-- notMagicChar = (\/= magicChar)+--+-- data PrintfAccum = PrintfAccum { done :: String, todo :: String }+--+-- instance Show x => Accumulator PrintfAccum x where+-- accumulate x (PrintfAccum done (_:todo)) = PrintfAccum+-- (done ++ show x ++ takeWhile notMagicChar todo)+-- (dropWhile notMagicChar todo)+-- accumulate _ acc = acc+--+-- printf' str = polyvariadic+-- (PrintfAccum (takeWhile notMagicChar str) (dropWhile notMagicChar str))+-- done+-- @+--+-- >>> printf' "aaa%bbb%ccc%ddd" "TEST" 123 True+-- "aaa\"TEST\"bbb123cccTrueddd"+class Polyvariadic accumulator result x where+ -- | Takes an accumulator @acc@, a function @f@, and an arbitrary+ -- number of additional arguments which will be accumulated in @acc@,+ -- which is finally passed to @f@.+ polyvariadic :: accumulator -> (accumulator -> result) -> x++-- | Accumulates the next argument+instance (Accumulator c i, Polyvariadic c b x) => Polyvariadic c b (i -> x) where+ polyvariadic a f x = polyvariadic (accumulate x a) f++-- | There are no more arguments to accumulate so the function is applied+-- to the 'Accumulator'+instance Polyvariadic accumulator result result where+ polyvariadic a f = f a+++---- application++-- | Application of function with an arbitrary number of arguments to the+-- elements of a list.+--+-- __Will raise an error if the list doesn't have enough elements__+--+-- ==== __Examples__+--+-- >>> apply ((+) :: Int -> Int -> Int) ([1,2] :: [Int]) :: Int+-- 3+class Apply a b x where+ apply' :: x -> [a] -> b++-- | The final type is not reached yet and the application continues+instance (Apply a b x) => Apply a b (a -> x) where+ apply' f (x:xs) = apply (f x) xs+ apply' _ _ = error "Not enough arguments in polyvariadic application"++-- | The final type is reached and the application terminates+instance Apply a b b where+ apply' f _ = f++-- | Like 'apply'' but with an arbitrary 'Foldable' instead if a list+apply :: (Apply a b x, Foldable t) => x -> t a -> b+apply f = apply f . toList+
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2017, Francesco Gazzetta++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 Francesco Gazzetta 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.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ polyvariadic.cabal view
@@ -0,0 +1,34 @@+-- Initial polyvariadic.cabal generated by cabal init. For further +-- documentation, see http://haskell.org/cabal/users-guide/++name: polyvariadic+version: 0.3.0.0+synopsis: Creation and application of polyvariadic functions+description: Creation and application of polyvariadic functions, see the docs for usage and examples+homepage: https://github.com/fgaz/polyvariadic+license: BSD3+license-file: LICENSE+author: Francesco Gazzetta+maintainer: francygazz@gmail.com+copyright: (C) Francesco Gazzetta 2017+category: Data+build-type: Simple+extra-source-files: ChangeLog.md+cabal-version: >=1.10++source-repository head+ type: git+ location: git://github.com/fgaz/polyvariadic.git++library+ exposed-modules: Data.Accumulator, Data.Function.Polyvariadic+ -- other-modules: + other-extensions: MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, GeneralizedNewtypeDeriving+ build-depends: base >=4.7 && <4.10+ , containers >=0.1 && <0.6+ if !impl(ghc >= 8.0)+ build-depends: semigroups == 0.18.*+ -- hs-source-dirs: + default-language: Haskell2010+ ghc-options: -Wall+