altcomposition (empty) → 0.2.1.0
raw patch · 4 files changed
+440/−0 lines, 4 filesdep +basedep +compositionsetup-changed
Dependencies added: base, composition
Files
- Data/AltComposition.hs +383/−0
- LICENSE +30/−0
- Setup.hs +2/−0
- altcomposition.cabal +25/−0
+ Data/AltComposition.hs view
@@ -0,0 +1,383 @@+-- | Compose functions with higher arity.+--+-- Ever tried something like this:+--+-- > (length . (++)) stringA stringB+--+-- Only to find out that you can't? The second function takes two parameters,+-- and as such the simple function composition does not work.+--+-- A well known solution to this problem is this fun operator:+--+-- > (.).(.) :: (c -> d) -> (a -> b -> c) -> (a -> b -> d)+--+-- And this is quite general:+--+-- > ((.).(.).(.)) :: (d -> e) -> (a -> b -> c -> d) -> (a -> b -> c -> e)+--+-- See the following link to gain a intuition for how this works:+-- <https://stackoverflow.com/questions/17585649/composing-function-composition-how-does-work>+--+-- However, in real use these suffer from some problems, namely:+--+-- * They cannot be used infix, even with ticks (at least in ghci).+--+-- * They are quite verbose.+--+-- Then, someone thought about using a new symbol instead:+--+-- > (.:) :: (c -> d) -> (a -> b -> c) -> (a -> b -> d)+--+-- And for each new parameter, you would add a dot+--+-- > (.:.) :: (d -> e) -> (a -> b -> c -> d) -> (a -> b -> c -> e)+--+-- And so on, to @.::@, @.::.@, etc. This is the approach taken by+-- the "composition" package, which inspired this one. It can be found at:+--+-- <http://hackage.haskell.org/package/composition>+--+-- This package is included in (and re-exported from) this AltComposition.+--+-- So, why define a new package?+--+-- It does not scale well for other combinations. Let say I want @(+) . (*)@,+-- a function that takes three parameters, uses the first two in the multiplication,+-- and then adds the third parameter with the result.+-- And what if I want to feed to the first binary function as the second parameter of+-- the second function?+--+-- The scheme proposed here is a little more verbose than the one from the+-- "composition" package, but it allows for a precise indication of where the+-- result of the first function is applied on the second function using the+-- @%@ symbol (remember printf @%@). So, the following operator:+--+-- > *%*.**+--+-- Takes a binary function, and composes it with a ternary function,+-- aplying its result as the middle parameter.+--+-- Its all a matter of opinion, and I strongly recomend that you use standard+-- haskell syntax instead of these, for more portable code.+--+-- Also, many of these verbose operators have simpler counterparts.+-- This is either noted as Deprecation, or a single note.+--+-- However, I still find myself writing the @*%.***@ operators myself, and I trust+-- the deprecations to warn me about the simpler alternatives.+--+-- If you need even higher arity, first check your code, then refactor your code,+-- and if you still need it, please send a pull request!+--+module Data.AltComposition (+ module Data.Composition+ , (%.**)+ , (%.***)+ , (%.****)+ , (%*.*)+ , (%*.**)+ , (%*.***)+ {-, (%*.****)-}+ , (*%.*)+ , (*%.**)+ , (*%.***)+ {-, (*%.****)-}+ , (%**.*)+ , (%**.**)+ , (%**.***)+ {-, (%**.****)-}+ , (*%*.*)+ , (*%*.**)+ , (*%*.***)+ {-, (*%*.****)-}+ , (**%.*)+ , (**%.**)+ , (**%.***)+ {-, (**%.****)-}+ , (%***.*)+ , (%***.**)+ , (?.)+ , (.$)+ , (§)+ , (&&\)+ , (||\)+ , for+ , with+ ) where++import Data.Composition+import qualified Control.Category as Cat++-- | Compose a binary function with a unitary function+--+-- /Note/: you should use idiomatic haskell instead+--+-- > (.).(.) :: (c -> d) -> (a -> b -> c) -> (a -> b -> d)+--+-- > (f %.** g) x y = f (g x y)+--+-- > (f .: g) x y = f (g x y)+(%.**) :: (c -> d) -> (a -> b -> c) -> a -> b -> d+(f %.** g) x y = f (g x y)+infixr 9 %.**++-- | Compose a ternary function with a unitary function+--+-- /Note/: you should use idiomatic haskell instead+--+-- > (.).(.).(.) :: (d -> e) -> (a -> b -> c -> d) -> (a -> b -> c -> e)+--+-- > (f %.*** g) x y z = f (g x y z)+--+-- > (f .:. g) x y z = f (g x y z)+(%.***) :: (d -> e) -> (a -> b -> c -> d) -> a -> b -> c -> e+(f %.*** g) x y z = f (g x y z)+infixr 9 %.***++-- | Compose a quaternary function with a unitary function+--+-- /Note/: you should use idiomatic haskell instead+--+-- > (.).(.).(.).(.) :: (e -> f) -> (a -> b -> c -> d -> e) -> (a -> b -> c -> d -> f)+--+-- > (f %.**** g) w x y z = f (g w x y z)+--+-- > (f .:: g) w x y z = f (g w x y z)+(%.****) :: (e -> f) -> (a -> b -> c -> d -> e) -> a -> b -> c -> d -> f+(f %.**** g) w x y z = f (g w x y z)+infixr 9 %.****+++-- | Compose a unary function with a binary function,+-- applying the result of the unary function as the+-- first parameter of the binary function.+--+-- /Note/: DO NOT USE. Equivalent to @.@.+--+-- > (f %*.* g) x y = f (g x) y <=> f . g+(%*.*) :: (b -> c -> d) -> (a -> b) -> a -> c -> d+(f %*.* g) x y = f (g x) y+infixr 9 %*.*+{-# DEPRECATED (%*.*) "This is the same as just (.)" #-}++-- | Compose a unary function with a binary function,+-- applying the result of the unary function as the+-- second parameter of the binary function.+--+-- /Note/: DO NOT USE. Equivalent to @flip f . g@.+--+-- > (f *%.* g) x y = f y (g x)+(*%.*) :: (b -> c -> d) -> (a -> c) -> a -> b -> d+(f *%.* g) x y = f y (g x)+infixr 9 *%.*++-- | Compose a unary function with a ternary function,+-- applying the result of the unary function as the+-- first parameter of the ternary function.+--+-- /Note/: DO NOT USE. Equivalent to @.@.+--+-- > (f %**.* g) x y z = f (g x) y z+(%**.*) :: (b -> c -> d -> e) -> (a -> b) -> a -> c -> d -> e+(f %**.* g) x y z = f (g x) y z+infix 9 %**.*+{-# DEPRECATED (%**.*) "This is the same as just (.)" #-}++-- | Compose a unary function with a ternary function,+-- applying the result of the unary function as the+-- second parameter of the ternary function.+--+-- > (f *%*.* g) x y z = f y (g x) z+(*%*.*) :: (b -> c -> d -> e) -> (a -> c) -> a -> b -> d -> e+(f *%*.* g) x y z = f y (g x) z+infix 9 *%*.*++-- | Compose a unary function with a ternary function,+-- applying the result of the unary function as the+-- third parameter of the ternary function.+--+-- > (f **%.* g) x y z = f y z (g x)+(**%.*) :: (b -> c -> d -> e) -> (a -> d) -> a -> b -> c -> e+(f **%.* g) x y z = f y z (g x)+infix 9 **%.*++-- | Compose a binary function with another binary function,+-- applying the result of the first binary function as the+-- first parameter of the second binary function.+--+-- /Note/: DO NOT USE. Equivalent to @flip f . g@.+--+-- > (f %*.** g) x y z = f (g x y) z+(%*.**) :: (c -> d -> e) -> (a -> b -> c) -> a -> b -> d -> e+(f %*.** g) x y z = f (g x y) z+infixr 9 %*.**+{-# DEPRECATED (%*.**) "Use f %.** g or .: instead" #-}++-- | Compose a binary function with another binary function,+-- applying the result of the first binary function as the+-- second parameter of the second binary function.+--+-- /Note/: DO NOT USE. Equivalent to @flip f .: g@ or @flip f %.** g@.+--+-- > (f *%.** g) x y z = f z (g x y)+(*%.**) :: (c -> d -> e) -> (a -> b -> d) -> a -> b -> c -> e+(f *%.** g) x y z = f z (g x y)+infixr 9 *%.**++-- | Compose a ternary function with a binary function,+-- applying the result of the ternary function as the+-- first parameter of the binary function.+--+-- > (f %*.*** g) x y w z = f (g x y w) z+(%*.***) :: (d -> e -> f) -> (a -> b -> c -> d) -> a -> b -> c -> e -> f+(f %*.*** g) x y w z = f (g x y w) z+infix 9 %*.***+{-# DEPRECATED (%*.***) "Use f %.*** g or f .:. instead" #-}++-- | Compose a ternary function with a binary function,+-- applying the result of the ternary function as the+-- second parameter of the binary function.+--+-- /Note/: DO NOT USE. Equivalent to @flip f .:. g@ or @flip f %.*** g@.+--+-- > (f *%.*** g) x y w z = f z (g x y w)+(*%.***) :: (d -> e -> f) -> (a -> b -> c -> e) -> a -> b -> c -> d -> f+(f *%.*** g) x y w z = f z (g x y w)+infix 9 *%.***++-- | Compose a binary function with a ternary function,+-- applying the result of the binary function as the+-- first parameter of the ternary function.+--+-- > (f %**.** g) x y w z = f (g x y) w z+(%**.**) :: (c -> d -> e -> f) -> (a -> b -> c) -> a -> b -> d -> e -> f+(f %**.** g) x y w z = f (g x y) w z+infix 9 %**.**+{-# DEPRECATED (%**.**) "Use f %.** g or f .: instead" #-}++-- | Compose a binary function with a ternary function,+-- applying the result of the binary function as the+-- second parameter of the ternary function.+--+-- /Note/: DO NOT USE. Equivalent to @flip f .: g@ or @flip f %.** g@.+--+-- > (f *%*.** g) x y w z = f w (g x y) z+(*%*.**) :: (c -> d -> e -> f) -> (a -> b -> d) -> a -> b -> c -> e -> f+(f *%*.** g) x y w z = f w (g x y) z+infix 9 *%*.**+{-# DEPRECATED (*%*.**) "Use f *%.** g instead" #-}++-- | Compose a binary function with a ternary function,+-- applying the result of the binary function as the+-- third parameter of the ternary function.+--+-- > (f **%.** g) x y w z = f w z (g x y)+(**%.**) :: (c -> d -> e -> f) -> (a -> b -> e) -> a -> b -> c -> d -> f+(f **%.** g) x y w z = f w z (g x y)+infix 9 **%.**++-- | Compose a ternary function with another ternary function,+-- applying the result of the first ternary function as the+-- first parameter of the last ternary function.+--+-- > (f %**.*** g) v w x y z = f (g v w x) y z+(%**.***) :: (f -> d -> e -> g) -> (a -> b -> c -> f) -> a -> b -> c -> d -> e -> g+(f %**.*** g) v w x y z = f (g v w x) y z+infix 9 %**.***+{-# DEPRECATED (%**.***) "Use f %.*** g or f .:. instead" #-}++-- | Compose a ternary function with another ternary function,+-- applying the result of the first ternary function as the+-- second parameter of the last ternary function.+--+-- /Note/: DO NOT USE. Equivalent to @flip f .:. g@ or @flip f %.*** g@.+--+-- > (f *%*.*** g) v w x y z = f y (g v w x) z+(*%*.***) :: (d -> f -> e -> g) -> (a -> b -> c -> f) -> a -> b -> c -> d -> e -> g+(f *%*.*** g) v w x y z = f y (g v w x) z+infix 9 *%*.***+{-# DEPRECATED (*%*.***) "Use f *%.*** g instead" #-}++-- | Compose a ternary function with another ternary function,+-- applying the result of the first ternary function as the+-- third parameter of the last ternary function.+--+-- > (f **%.*** g) v w x y z = f y z (g v w x)+(**%.***) :: (d -> e -> f -> g) -> (a -> b -> c -> f) -> a -> b -> c -> d -> e -> g+(f **%.*** g) v w x y z = f y z (g v w x)+infix 9 **%.***++-- | Compose a unary function with a quaternary function,+-- applying the result of the first unary function as the+-- first parameter of the quaternary function.+--+-- > (f %***.* g) w x y z = f (g w) x y z+(%***.*) :: (f -> b -> c -> d -> g) -> (a -> f) -> a -> b -> c -> d -> g+(f %***.* g) w x y z = f (g w) x y z+infix 9 %***.*+{-# DEPRECATED (%***.*) "This is the same as just (.)" #-}++-- | Compose a binary function with a quaternary function,+-- applying the result of the first binary function as the+-- first parameter of the quaternary function.+--+-- > (f %***.** g) v w x y z = f (g v w) x y z+(%***.**) :: (f -> c -> d -> e -> g) -> (a -> b -> f) -> a -> b -> c -> d -> e -> g+(f %***.** g) v w x y z = f (g v w) x y z+infix 9 %***.**+{-# DEPRECATED (%***.**) "This is the same as just %.** or .:" #-}++-- | Conditional composition. Borrowed (and modified) from+-- <http://hackage.haskell.org/package/cond-0.4.0.2>+-- If the predicate is False, 'id' is returned+-- instead of the second argument. This function, for example, can be used to+-- conditionally add functions to a composition chain.+(?.) :: (Cat.Category cat) => Bool -> cat a a -> cat a a+p ?. c = if p then c else Cat.id+{-# INLINE (?.) #-}++-- | Slightly Lower fixity function composition for use with @'?.'@.+(.$) :: (b -> c) -> (a -> b) -> (a -> c)+(.$) = (Prelude..)+infixl 8 .$++-- | Just like (@'$'@), but with higher precedence than (@'<>'@), but still lower+-- than (@'.'@). Similar to "Diagrams.Util" @'#'@, but without flipped arguments.+{-# INLINE (§) #-}+(§) :: (a -> b) -> a -> b+f § x = f x+infixr 8 §++-- | Group conditions with @'&&'@. Useful for filter.+--+-- /Note/: an easy mnemonic to remember is that operators ending in \\ (lambda)+-- imply that their parameters are functions instead of values (in this particular+-- case, boolean tests)+--+-- > (f &&\ g) x = f x && g x+(&&\) :: (a -> Bool) -> (a -> Bool) -> (a -> Bool)+(f &&\ g) x = f x && g x+infixr 3 &&\{- This comment tells CPP to behave -}++-- | Group conditions with @'||'@ Useful for filter.+--+-- /Note/: an easy mnemonic to remember is that operators ending in \\ (lambda)+-- imply that their parameters are functions instead of values (in this particular+-- case, boolean tests)+--+-- > (f ||\ g) x = f x || g x+(||\) :: (a -> Bool) -> (a -> Bool) -> (a -> Bool)+(f ||\ g) x = f x || g x+infixr 2 ||\{- This comment tells CPP to behave -}++-- | fmap with its arguments reversed.+--+-- <http://www.reddit.com/r/haskell/comments/qy990/suggestion_for_flip_map/>+--+-- > for = flip fmap+-- > with = flip fmap+for,with :: (Functor f) => f a -> (a -> b) -> f b+for = flip fmap+with= flip fmap++
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2014, João Cristóvão++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 João Cristóvão 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
+ altcomposition.cabal view
@@ -0,0 +1,25 @@+name: altcomposition+version: 0.2.1.0+synopsis: Alternative combinators for unorthodox function composition+-- description: +homepage: https://github.com/jcristovao/altcomposition+license: BSD3+license-file: LICENSE+author: João Cristóvão+maintainer: jmacristovao@gmail.com+category: Data+build-type: Simple++-- Extra files to be distributed with the package, such as examples or a +-- README.+-- extra-source-files: ++cabal-version: >=1.16++library+ exposed-modules: Data.AltComposition+ build-depends: base >= 4.0 && < 4.8+ , composition >= 1.0 && < 1.1+ default-language: Haskell2010+ ghc-options: -Wall+