flow 1.0.1 → 1.0.2
raw patch · 5 files changed
+170/−151 lines, 5 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
Files
- CHANGELOG.md +4/−0
- Flow.hs +134/−111
- FlowBench.hs +15/−15
- README.md +10/−17
- flow.cabal +7/−8
CHANGELOG.md view
@@ -2,6 +2,10 @@ Flow uses [Semantic Versioning][]. +## v1.0.2 (2015-10-04)++- Updated documentation.+ ## v1.0.1 (2015-06-04) - Updated documentation.
Flow.hs view
@@ -1,81 +1,70 @@ {- |- Flow is a package that provides functions and operators for writing more- understandable Haskell. It's an alternative to some common idioms like- @($)@ for function application and @(.)@ for function composition.+ Flow provides operators for writing more understandable Haskell. It is an+ alternative to some common idioms like ('Prelude.$') for function+ application and ('Prelude..') for function composition. Flow is designed to be imported unqualified. It does not export anything- that conflicts with- <http://hackage.haskell.org/package/base the base package>.+ that conflicts with the base package. >>> import Flow - For more information about Flow, please visit- <http://taylor.fausak.me/flow/ the official site>.+ == Rationale++ I think that Haskell can be hard to read. It has two operators for applying+ functions. Both are not really necessary and only serve to reduce+ parentheses. But they make code hard to read. People who do not already+ know Haskell have no chance of guessing what @foo $ bar@ or @baz & qux@+ mean.++ Those that do know Haskell are forced to read lines forwards and backwards+ at the same time, thanks to function composition. Even something simple,+ like finding the minimum element, bounces around: @f = head . sort@.++ I think we can do better. By using directional operators, we can allow+ readers to move their eye in only one direction, be that left-to-right or+ right-to-left. And by using idioms common in other programming languages,+ we can allow people who aren't familiar with Haskell to guess at the+ meaning.++ So instead of ('Prelude.$'), I propose ('<|'). It is a pipe, which anyone+ who has touched a Unix system should be familiar with. And it points in the+ direction it sends arguments along. Similarly, replace ('Prelude.&') with+ ('|>'). And for composition, ('<.') replaces ('Prelude..'). I would have+ preferred @<<@, but its counterpart @>>@ is taken by Haskell's syntax.+ So-called "backwards" composition is normally expressed with+ ('Control.Category.>>>'), which Flow provides as ('.>'). -} module Flow ( -- * Function application- apply, (|>), (<|),+ (|>), (<|), apply, -- * Function composition- compose, (.>), (<.),+ (.>), (<.), compose, -- * Strict function application- apply', (!>), (<!),+ (!>), (<!), apply', ) where import Prelude (seq) {- $setup >>> import Prelude- >>> let f = (+ 2)- >>> let g = (* 2)- >>> let h = (^ 2)+ >>> let f = (+ 3)+ >>> let g = (* 3)+ >>> let h = (^ 3) -} {- |- prop> apply x f == f x-- <https://en.wikipedia.org/wiki/Function_application Function application>.- This is like the 'Prelude.$' operator.-- >>> apply False not- True-- Using this function with many arguments is cumbersome. Use '|>' or '<|'- instead.-- >>> False `apply` not `apply` fromEnum- 1-- This function usually isn't necessary since @'apply' x f@ is the same as- @f x@. However it can come in handy when working with higher-order- functions.-- >>> map (apply False) [not, id]- [True,False]--}-apply :: a -> (a -> b) -> b-apply x f = f x--{- | prop> (x |> f) == f x- prop> (x |> f |> g) == g (f x) - Left-associative 'apply' operator. This is like a flipped version of the- 'Prelude.$' operator. Read it as "apply forward" or "pipe into".-- >>> False |> not- True-- Since this operator has such low precedence, it can be used to remove- parentheses from complicated expressions.+ prop> (x |> f |> g) == g (f x) - >>> False |> not |> fromEnum- 1+ Left-associative 'apply' operator. Read as "apply forward" or "pipe into".+ Use this to create long chains of computation that suggest which direction+ things move in. - This operator can be used with higher-order functions, but 'apply' might be- clearer.+ >>> 3 |> succ |> recip |> negate+ -0.25 - >>> map (False |>) [not, id]- [True,False]+ Or use it anywhere you would use ('Prelude.&'). -} infixl 0 |> (|>) :: a -> (a -> b) -> b@@ -83,62 +72,50 @@ {- | prop> (f <| x) == f x- prop> (g <| f <| x) == g (f x) - Right-associative 'apply' operator. This is like the 'Prelude.$' operator.- Read it as "apply backward" or "pipe from".-- >>> not <| False- True-- This operator can be used to remove parentheses from complicated- expressions because of its low precedence.+ prop> (g <| f <| x) == g (f x) - >>> fromEnum <| not <| False- 1+ Right-associative 'apply' operator. Read as "apply backward" or "pipe+ from". Use this to create long chains of computation that suggest which+ direction things move in. You may prefer this operator over ('|>') for+ 'Prelude.IO' actions since it puts the last function first. - With higher-order functions, this operator is a clearer alternative to- @flip 'apply'@.+ >>> print <| negate <| recip <| succ <| 3+ -0.25 - >>> map (<| False) [not, id]- [True,False]+ Or use it anywhere you would use ('Prelude.$'). -} infixr 0 <| (<|) :: (a -> b) -> a -> b f <| x = apply x f {- |- prop> compose f g x == g (f x)-- <https://en.wikipedia.org/wiki/Function_composition Function composition>.- This is like the 'Prelude..' operator.-- >>> (compose not fromEnum) False- 1+ prop> apply x f == f x - Composing many functions together quickly becomes unwieldy. Use '.>' or- '<.' instead.+ Function application. This function usually isn't necessary, but it can be+ more readable than some alternatives when used with higher-order functions+ like 'Prelude.map'. - >>> (not `compose` fromEnum `compose` succ) False- 2+ >>> map (apply 2) [succ, recip, negate]+ [3.0,0.5,-2.0] -}-compose :: (a -> b) -> (b -> c) -> (a -> c)-compose f g = \ x -> g (f x)+apply :: a -> (a -> b) -> b+apply x f = f x {- | prop> (f .> g) x == g (f x)- prop> (f .> g .> h) x == h (g (f x)) - Left-associative 'compose' operator. This is like a flipped version of the- 'Prelude..' operator. Read it as "compose forward" or "and then".+ prop> (f .> g .> h) x == h (g (f x)) - >>> (not .> fromEnum) False- 1+ Left-associative 'compose' operator. Read as "compose forward" or "and+ then". Use this to create long chains of computation that suggest which+ direction things move in. - Thanks to its high precedence, composing many functions together is easy.+ >>> let f = succ .> recip .> negate+ >>> f 3+ -0.25 - >>> (not .> fromEnum .> succ) False- 2+ Or use it anywhere you would use ('Control.Category.>>>'). -} infixl 9 .> (.>) :: (a -> b) -> (b -> c) -> (a -> c)@@ -146,42 +123,56 @@ {- | prop> (g <. f) x == g (f x)- prop> (h <. g <. f) x == h (g (f x)) - Right-associative 'compose' operator. This is like the 'Prelude..'- operator. Read it as "compose backward" or "but first".+ prop> (h <. g <. f) x == h (g (f x)) - >>> (fromEnum <. not) False- 1+ Right-associative 'compose' operator. Read as "compose backward" or "but+ first". Use this to create long chains of computation that suggest which+ direction things move in. You may prefer this operator over ('.>') for+ 'Prelude.IO' actions since it puts the last function first. - Composing many functions together is easy thanks to its high precedence.+ >>> let f = print <. negate <. recip <. succ+ >>> f 3+ -0.25 - >>> (succ <. fromEnum <. not) False- 2+ Or use it anywhere you would use ('Prelude..'). -} infixr 9 <. (<.) :: (b -> c) -> (a -> b) -> (a -> c) g <. f = compose f g {- |- prop> apply' x f == seq x (f x)+ prop> compose f g x == g (f x) - Strict function application. This is like the 'Prelude.$!' operator.+ Function composition. This function usually isn't necessary, but it can be+ more readable than some alternatives when used with higher-order functions+ like 'Prelude.map'. - >>> apply' undefined (const False)- *** Exception: Prelude.undefined+ >>> let fs = map (compose succ) [recip, negate]+ >>> map (apply 3) fs+ [0.25,-4.0] -}-apply' :: a -> (a -> b) -> b-apply' x f = seq x (apply x f)+compose :: (a -> b) -> (b -> c) -> (a -> c)+compose f g = \ x -> g (f x) {- | prop> (x !> f) == seq x (f x)- prop> (x !> f !> g) == seq x (g (seq x (f x))) - Left-associative 'apply'' operator. This is like a flipped version of the- 'Prelude.$!' operator.+ prop> (x !> f !> g) == let y = seq x (f x) in seq y (g y) - >>> undefined !> const False+ Left-associative 'apply'' operator. Read as "strict apply forward" or+ "strict pipe info". Use this to create long chains of computation that+ suggest which direction things move in.++ >>> 3 !> succ !> recip !> negate+ -0.25++ The difference between this and ('|>') is that this evaluates its argument+ before passing it to the function.++ >>> undefined |> const True+ True+ >>> undefined !> const True *** Exception: Prelude.undefined -} infixl 0 !>@@ -190,14 +181,46 @@ {- | prop> (f <! x) == seq x (f x)- prop> (g <! f <! x) == seq x (g (seq x (f x))) - Right-associative 'apply'' operator. This is like the 'Prelude.$!'- operator.+ prop> (g <! f <! x) == let y = seq x (f x) in seq y (g y) - >>> const False <! undefined+ Right-associative 'apply'' operator. Read as "strict apply backward" or+ "strict pipe from". Use this to create long chains of computation that+ suggest which direction things move in. You may prefer this operator over+ ('!>') for 'Prelude.IO' actions since it puts the last function first.++ >>> print <! negate <! recip <! succ <! 3+ -0.25++ The difference between this and ('<|') is that this evaluates its argument+ before passing it to the function.++ >>> const True <| undefined+ True+ >>> const True <! undefined *** Exception: Prelude.undefined -} infixr 0 <! (<!) :: (a -> b) -> a -> b f <! x = apply' x f++{- |+ prop> apply' x f == seq x (f x)++ Strict function application. This function usually isn't necessary, but it+ can be more readable than some alternatives when used with higher-order+ functions like 'Prelude.map'.++ >>> map (apply' 2) [succ, recip, negate]+ [3.0,0.5,-2.0]++ The different between this and 'apply' is that this evaluates its argument+ before passing it to the function.++ >>> apply undefined (const True)+ True+ >>> apply' undefined (const True)+ *** Exception: Prelude.undefined+-}+apply' :: a -> (a -> b) -> b+apply' x f = seq x (apply x f)
FlowBench.hs view
@@ -6,30 +6,30 @@ main :: IO () main = defaultMain [ bgroup "application"- [ bench "f x" $ whnf f x- , bench "apply x f" $ whnf (apply x) f- , bench "x |> f" $ whnf (x |>) f- , bench "f <| x" $ whnf (<| x) f+ [ bench "f x" (whnf f x)+ , bench "apply x f" (whnf (apply x) f)+ , bench "x |> f" (whnf (x |>) f)+ , bench "f <| x" (whnf (<| x) f) ] , bgroup "composition"- [ bench "f . g" $ whnf (f .) g- , bench "compose f g" $ whnf (compose f) g- , bench "f .> g" $ whnf (f .>) g- , bench "g <. f" $ whnf (<. f) g+ [ bench "f . g" (whnf (f .) g)+ , bench "compose f g" (whnf (compose f) g)+ , bench "f .> g" (whnf (f .>) g)+ , bench "g <. f" (whnf (<. f) g) ] , bgroup "strict application"- [ bench "seq x (f x)" $ whnf (seq x) (f x)- , bench "apply' x f" $ whnf (apply' x) f- , bench "x !> f" $ whnf (x !>) f- , bench "f <! x" $ whnf (<! x) f+ [ bench "seq x (f x)" (whnf (seq x) (f x))+ , bench "apply' x f" (whnf (apply' x) f)+ , bench "x !> f" (whnf (x !>) f)+ , bench "f <! x" (whnf (<! x) f) ] ] x :: Int-x = 2+x = 3 f :: Int -> Int-f = (+ 2)+f y = y + 3 g :: Int -> Int-g = (* 2)+g y = y * 3
README.md view
@@ -9,12 +9,13 @@ --- Flow is a package that provides functions and operators for writing more-understandable Haskell. It's an alternative to some common idioms like+understandable Haskell. It is an alternative to some common idioms like [`($)`][] for function application and [`(.)`][] for function composition. - [Requirements](#requirements) - [Installation](#installation) - [Usage](#usage)+ - [Cheat sheet](#cheat-sheet) ## Requirements @@ -30,14 +31,7 @@ build-depends: flow ==1.0.* ``` -For other use cases, install it with Cabal.--``` sh-$ cabal install 'flow ==1.0.*'-```--Flow uses [Semantic Versioning][]. See [the change log][] for a detailed list-of changes.+See [the change log][] for a detailed list of changes. ## Usage @@ -48,29 +42,28 @@ import Flow ``` -Here is a quick overview of the functions and operators that Flow provides.+### Cheat sheet Flow | Base --------------- | --------------`apply x f` | `f x` `x |> f` | `x & f` `f <| x` | `f $ x`-`compose f g x` | `g (f x)`+`apply x f` | `f x` `f .> g` | `f >>> g` `g <. f` | `g . f`-`apply' x f` | `seq x (f x)`+`compose f g x` | `g (f x)` `x !> f` | - `f <! x` | `f $! x`+`apply' x f` | `seq x (f x)` For more information about Flow, please read [the Haddock documentation][]. [flow]: http://taylor.fausak.me/flow/-[version]: https://img.shields.io/hackage/v/flow.svg?label=version&style=flat-square-[build]: https://img.shields.io/travis/tfausak/flow/master.svg?label=build&style=flat-square-[dependencies]: https://img.shields.io/hackage-deps/v/flow.svg?label=dependencies&style=flat-square+[version]: https://img.shields.io/hackage/v/flow.svg?label=version+[build]: https://img.shields.io/travis/tfausak/flow/master.svg?label=build+[dependencies]: https://img.shields.io/hackage-deps/v/flow.svg?label=dependencies [`($)`]: http://hackage.haskell.org/package/base-4.8.0.0/docs/Prelude.html#v:-36- [`(.)`]: http://hackage.haskell.org/package/base-4.8.0.0/docs/Prelude.html#v:.-[semantic versioning]: http://semver.org/spec/v2.0.0.html [the change log]: CHANGELOG.md [the base package]: http://hackage.haskell.org/package/base [the haddock documentation]: https://hackage.haskell.org/package/flow/docs/Flow.html
flow.cabal view
@@ -1,5 +1,5 @@ name: flow-version: 1.0.1+version: 1.0.2 cabal-version: >=1.8 build-type: Simple license: MIT@@ -10,12 +10,9 @@ bug-reports: https://github.com/tfausak/flow/issues synopsis: Write more understandable Haskell. description:- Flow is a package that provides functions and operators for writing more- understandable Haskell. It's an alternative to some common idioms like- @($)@ for function application and @(.)@ for function composition.- .- For more information, please visit- <http://taylor.fausak.me/flow/ the official site>.+ Flow provides operators for writing more understandable Haskell. It is an+ alternative to some common idioms like (@$@) for function application and+ (@.@) for function composition. category: Combinators, Functions, Utility author: Taylor Fausak <taylor@fausak.me> extra-source-files:@@ -39,7 +36,7 @@ build-depends: base -any, flow -any,- doctest >= 0.9 && <0.11,+ doctest >=0.9 && <0.11, QuickCheck ==2.*, template-haskell ==2.* ghc-options: -Wall@@ -51,4 +48,6 @@ base -any, flow -any, criterion ==1.*+ other-modules:+ Flow ghc-options: -Wall