packages feed

flow-er (empty) → 1.0.0

raw patch · 17 files changed

+856/−0 lines, 17 filesdep +QuickCheckdep +basedep +doctestsetup-changed

Dependencies added: QuickCheck, base, doctest, flow, flow-er

Files

+ LICENSE view
@@ -0,0 +1,21 @@+The MIT License (MIT)++Copyright (c) 2016 Brooklyn Zelenka++Permission is hereby granted, free of charge, to any person obtaining a copy+of this software and associated documentation files (the "Software"), to deal+in the Software without restriction, including without limitation the rights+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+copies of the Software, and to permit persons to whom the Software is+furnished to do so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in all+copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+SOFTWARE.
+ README.md view
@@ -0,0 +1,3 @@+# :sweat_drops: flower+## \ˈflō'ər\+More [Flow](https://hackage.haskell.org/package/flow)
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ flow-er.cabal view
@@ -0,0 +1,75 @@+name:                  flow-er+version:               1.0.0+synopsis:              Initial project template from stack+description:           Please see README.md+homepage:              https://github.com/expede/flower#README++license:               MIT+license-file:          LICENSE++author:                Brooklyn Zelenka+maintainer:            bez@brooklynzelenka.com++category:              Combinators, Functions, Utility+build-type:            Simple++extra-source-files:    README.md+cabal-version:         >= 1.24++library+  hs-source-dirs:      src+  exposed-modules:     Control.Flower++                     , Control.Flower.Apply+                     , Control.Flower.Apply.Lazy+                     , Control.Flower.Apply.Strict++                     , Control.Flower.Compose++                     , Control.Flower.Functor+                     , Control.Flower.Functor.Lazy+                     , Control.Flower.Functor.Strict++                     , Control.Flower.Applicative+                     , Control.Flower.Applicative.Lazy+                     , Control.Flower.Applicative.Strict++                     , Control.Flower.Monad++  build-depends:       base == 4.*+                     , flow ==1.0.*+  hs-source-dirs:      src+  ghc-options:         -Wall -fno-warn-orphans+  default-language:    Haskell2010++-- test-suite flower-test+--   type:                exitcode-stdio-1.0+--   hs-source-dirs:      test+--   main-is:             Spec.hs+--   ghc-options:         -Wall -threaded -rtsopts -with-rtsopts=-N+--   default-language:    Haskell2010+--   build-depends:       base+--                      , flow ==1.0.*+--                      , flower+--                      , tasty >= 0.10 && < 1.0+--                      , tasty-hunit      >= 0.9 && < 1.0+--                      , tasty-smallcheck >= 0.8 && < 1.0+--                      , tasty-quickcheck >= 0.8 && < 1.0+--                      , smallcheck       >= 1.1 && < 2.0+--                      , checkers         >= 0.4 && < 1.0++test-suite doctests+  type:                exitcode-stdio-1.0+  default-language:    Haskell2010+  ghc-options:        -Wall +RTS -N -RTS -threaded+  hs-source-dirs:      test+  main-is:             doctests.hs+  build-depends:       base+                     , QuickCheck ==2.8.*+                     , doctest >= 0.9 && < 1.0+                     , flow ==1.0.*+                     , flow-er++source-repository head+  type:     git+  location: https://github.com/expede/flower.git
+ src/Control/Flower.hs view
@@ -0,0 +1,69 @@+{-|+Module      : Control.Flower+Description : Modern, readable, directional Haskell++== Use++>>> import Control.Flower++== Rationale++> Mathematics, rightly viewed, possesses not only truth,+> but supreme beauty -- a beauty cold and austere, like that of sculpture,+> without appeal to any part of our weaker nature, without the gorgeous+> trappings of painting or music, yet sublimely pure, and capable of a stern+> perfection such as only the greatest art can show. The true spirit of delight,+> the exaltation, the sense of being more than Man, which is the touchstone of+> the highest excellence, is to be found in mathematics as surely as poetry.+> - Bertrand Russell, "The Study of Mathematics"++Inspired by the wonderful @Flow@ package, Flower provides directional operators+for many common Haskell functions.++With the pipe operator ('|>') proliferating through OCaml, F#, and Elixir,+it's becoming clear which way the wind is blowing. A dataflow model is very+natural to functional programming _____.++Thinking in Haskell is multidimensional, reading forwards and backwards,+and through levels of abstraction. This is extremely powerful, but does introduce+a leaning curve (in grade school, when starting with Haskell, or both).++Here, instead of 'Prelude.$', we use '<|', or reversed with '|>'. Instead of+'Prelude.<$>', we use '<$', and reversed '$>'. Many of the combinators are+built up from meaningful character combinations. One such example is 'Prelude.lift2',+which is translated into '<$**'. '<$**', as 'f <$ a <* b <* c'.++Please do note that 'Control.Flower' exposes conflicting combinators versus the+standard 'Prelude'.++=== Teaching+Teaching concepts becomes simplified by providing a visual aid. Many of the operators+are made up of simpler symbols, much in the same way as the @Lens@ library.++One common challenge when teaching Haskell is showing what an applicative+or monad "mean". By using a progressive, modular picture of each abstraction,+we help build the intuition.++=== Reading+A focus on a single direction of data flow makes code easy to follow.++=== Simplify+All `lift`s (`fmap`, `liftA*` and `liftM*`) are unified as `lift*`.++-}+module Control.Flower (+  -- * Basic data flow+  module Control.Flower.Apply,+  module Control.Flower.Compose,++  -- * Functors+  module Control.Flower.Functor,+  module Control.Flower.Applicative,+  module Control.Flower.Monad+) where++import Control.Flower.Apply+import Control.Flower.Compose+import Control.Flower.Functor+import Control.Flower.Applicative+import Control.Flower.Monad
+ src/Control/Flower/Applicative.hs view
@@ -0,0 +1,7 @@+module Control.Flower.Applicative (+  module Control.Flower.Applicative.Lazy,+  module Control.Flower.Applicative.Strict+) where++import Control.Flower.Applicative.Lazy+import Control.Flower.Applicative.Strict
+ src/Control/Flower/Applicative/Lazy.hs view
@@ -0,0 +1,113 @@+{-|+Module      : Control.Flower.Applicative.Lazy+Description : Combinators for directional lazy applicative functors+-}++module Control.Flower.Applicative.Lazy (+  ap,+  lift2, lift3,+  (<*), (*>),+  (<$*), (*$>),+  (<$**), (**$>)+) where++import Prelude hiding ((<*), (*>))+import Control.Applicative hiding ((<*), (*>))++{- $setup+>>> import Control.Flower.Apply++>>> let x = Just 3+>>> let y = Just 4++>>> let f = (+2)+>>> let g = (*2)+>>> let h = (+)+-}++{-| A simple alias for 'Prelude.<*>'++>>> ap (Just (+1)) (Just 4)+Just 5++-}+ap :: Applicative f => f (a -> b) -> f a -> f b+ap = (<*>)++{-| Right-associative, left-flowing applicative operator++>>> Just (+1) <* Just 4+Just 5++-}+infixr 4 <*+(<*) :: Applicative f => f (a -> b) -> f a -> f b+(<*) = ap++{-| Left-associative, right-flowing applicative operator++>>> Just 4 *> Just (+1)+Just 5++-}+infixl 4 *>+(*>) :: Applicative f => f a -> f (a -> b) -> f b+(*>) = flip ap++{-| An alias for 'Control.Applicative.lift2', updating with unified "lift" naming++>>> lift2 (+) (Just 4) (Just 1)+Just 5++-}+lift2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c+lift2 = liftA2++{-| Right-associative, left-flowing 'lift2' operator++>>> (+) <$* Just 4 |< Just 1+Just 5++-}+infixr 4 <$*+(<$*) :: Applicative f => (a -> b -> c) -> f a -> f b -> f c+(<$*) = lift2++{-| Left-associative, right-flowing 'lift2' operator++>>> Just 4 >| Just 1 *$> (+)+Just 5++-}+infixl 4 *$>+(*$>) :: Applicative f => f a -> (a -> b -> c) -> f b -> f c+(*$>) = flip lift2++{-| An alias for 'Control.Applicative.lift3', updating with unified "lift" naming++>>> lift3 (\x y z -> x * y * z) (Just 4) (Just 3) (Just 2)+Just 24++-}+lift3 :: Applicative f => (a -> b -> c -> d) -> f a -> f b -> f c -> f d+lift3 = liftA3++{-| Right-associative, left-flowing 'lift3' operator++>>> (\x y z -> x * y * z) <$** Just 4 |< Just 3 |< Just 2+Just 24++-}+infixr 4 <$**+(<$**) :: Applicative f => (a -> b -> c -> d) -> f a -> f b -> f c -> f d+f <$** x = \y z -> lift3 f x y z -- AKA f <$ a <* b <* c++{-| Left-associative, right-flowing 'lift3' operator++>>> Just 2 >| Just 3 >| Just 4 **$> \x y z -> x * y * z+Just 24++-}+infixl 4 **$>+(**$>) :: Applicative f => f a -> (a -> b -> c -> d) -> f b -> f c -> f d+x **$> f = \y z -> lift3 f x y z
+ src/Control/Flower/Applicative/Strict.hs view
@@ -0,0 +1,83 @@+{-|+Module      : Control.Flower.Applicative.Strict+Description : Combinators for directional strict applicative functors+-}++module Control.Flower.Applicative.Strict (+  lift2',+  (<!$*), (*$!>),+  (<!$**), (**$!>)+) where++import Prelude hiding ((<*), (*>))+import Control.Flower.Functor.Strict+import Control.Flower.Applicative.Lazy++{- $setup+>>> import Control.Flower.Apply++>>> let x = Just 3+>>> let y = Just 4++>>> let f = (+2)+>>> let g = (*2)+>>> let h = (+)+-}++{-| An alias for 'Control.Applicative.lift2', updating with unified "lift" naming++>>> lift2' (+) (Just 4) (Just 1)+Just 5++-}+lift2' :: Monad m => (a -> b -> c) -> m a -> m b -> m c+lift2' f a b = (f <!$ a) <* b++{-| Right-associative, left-flowing `lift2'` operator++>>> (+) <!$* Just 4 |< Just 1+Just 5++-}+infixr 4 <!$*+(<!$*) :: Monad m => (a -> b -> c) -> m a -> m b -> m c+f <!$* a = \b -> lift2' f a b++{-| Left-associative, right-flowing `lift2'` operator++>>> Just 1 >| Just 4 *$!> (+)+Just 5++-}+infixl 4 *$!>+(*$!>) :: Monad m => m a -> (a -> b -> c) -> m b -> m c+a *$!> f = \b -> lift2' f a b++{-| A strict version of 'Control.Flower.Applicative.Lazy.lift3'++>>> lift3' (\x y z -> x * y * z) (Just 4) (Just 3) (Just 2)+Just 24++-}+lift3' :: Monad m => (a -> b -> c -> d) -> m a -> m b -> m c -> m d+lift3' f a b c = ((f <!$ a) <* b) <* c++{-| Right-associative, left-flowing `lift3'` operator++>>> (\x y z -> x * y * z) <!$** Just 4 |< Just 3 |< Just 2+Just 24++-}+infixr 4 <!$**+(<!$**) :: Monad m => (a -> b -> c -> d) -> m a -> m b -> m c -> m d+f <!$** x = \y z -> lift3' f x y z -- AKA f <$ a <* b <* c++{-| Left-associative, right-flowing `lift3'` operator++>>> Just 2 >| Just 3 >| Just 4 **$!> \x y z -> x * y * z+Just 24++-}+infixl 4 **$!>+(**$!>) :: Monad m => m a -> (a -> b -> c -> d) -> m b -> m c -> m d+x **$!> f = \y z -> lift3' f x y z
+ src/Control/Flower/Apply.hs view
@@ -0,0 +1,7 @@+module Control.Flower.Apply (+  module Control.Flower.Apply.Lazy,+  module Control.Flower.Apply.Strict+) where++import Control.Flower.Apply.Lazy+import Control.Flower.Apply.Strict
+ src/Control/Flower/Apply/Lazy.hs view
@@ -0,0 +1,101 @@+{-|+Module      : Control.Flower.Apply.Lazy+Description : Combinators for directional lazy application+-}++module Control.Flower.Apply.Lazy (+  (<|), (|>),+  (|<), (>|)+) where++{- $setup+>>> let x = 3+>>> let y = 4++>>> let f = (+2)+>>> let g = (*2)+>>> let h = (+)+-}++{-| Left-flowing application, equivalent to 'prelude.$'.++Read as "backwards application", "pipe from", or "pull from".++>>> (f <| x) == f x+True++>>> (g <| f <| x) == g (f x)+True++This operator can be chained together to show the dataflow through a series of functions++>>> negate <| succ <| 3 :: Int+-4++-}+infixr 0 <|+(<|) :: (a -> b) -> a -> b+f <| x = f x++{-| Right-flowing application, equivalent to 'prelude.$'.++Read as "forwards application" or "pipe into".++>>> (x |> f) == f x+True++>>> (x |> f |> g) == g (f x)+True++This operator can be chained together to show the dataflow through a series of functions++>>> 3 |> succ |> negate :: Int+-4++-}+infixl 0 |>+(|>) :: a -> (a -> b) -> b+x |> f = f x++{-| Left-flowing, left-associative application++Read as "pipe into the result of".+It may seem odd in trivial cases, but is useful for functions that take more than one argument,+as it will partially apply arguments one at a time.++>>> (f |< x) == f x+True++>>> (h |< y |< x) == ((h <| y) <| x)+True++Can be chained together to show the dataflow through a series of functions++>>> (+) |< 3 |< 5 :: Int+8++-}+infixl 0 |<+(|<) :: (a -> b) -> a -> b+(|<) = (<|)++{-| Right-flowing, right-associative application++Read as "pipe from the result of", or "pull from the result from".+It may seem odd in trivial cases, but is useful for functions that take more than one argument.++>>> (x >| f) == f x+True++>>> (x >| y >| h) == (x |> (y |> h))+True++Can be chained together to show the dataflow through a series of functions++>>> 3 >| 5 >| (+)+8++-}+infixr 0 >|+(>|) :: a -> (a -> b) -> b+(>|) = (|>)
+ src/Control/Flower/Apply/Strict.hs view
@@ -0,0 +1,102 @@+{-|+Module      : Control.Flower.Apply.Strict+Description : Combinators for directional lazy application+-}+module Control.Flower.Apply.Strict (+  (<!), (!>),+  (!<), (>!)+) where++{- $setup+>>> let x = 3+>>> let y = 4++>>> let f = (+2)+>>> let g = (*2)+>>> let h = (+)+-}+++{-| Left-flowing strict application, equivalent to 'prelude.$'.++Read as "backwards strict application", "strict pipe from", or "strict pull from".++>>> (f <! x) == f x+True++>>> (g <! f <! x) == g (f x)+True++This operator can be chained together to show the dataflow through a series of functions++>>> negate <! succ <! 3 :: Int+-4++-}+infixl 0 !>+(!>) :: a -> (a -> b) -> b+x !> f = f $! x++{-| Right-flowing strict application, equivalent to 'prelude.$'.++Read as "forward strict application" or "strict pipe into".++>>> (x !> f) == f x+True++>>> (x !> f !> g) == g (f x)+True++This operator can be chained together to show the dataflow through a series of functions++>>> 3 !> succ !> negate :: Int+-4++-}+infixr  0 <!+(<!) :: (a -> b) -> a -> b+f <! x = f $! x++{-| Left-flowing, left-associative strict application++Read as "strictly pipe into the result of".+It may seem odd in trivial cases, but is useful for functions that take more than one argument,+as it will partially apply arguments one at a time.++>>> (f !< x) == f x+True++>>> (h !< y !< x) == ((h <! y) <! x)+True++Can be chained together to show the dataflow through a series of functions++>>> (+) !< 3 !< 5 :: Int+8++-}++infixl 1 !<+(!<) :: (a -> b) -> a -> b+(!<) = (<!)++{-| Right-flowing, right-associative strict application++Read as "strictly pipe from the result of", or "strictly pull from the result from".+It may seem odd in trivial cases, but is useful for functions that take more than one argument.++>>> (x >! f) == f x+True++>>> (x >! y >! h) == (x !> (y !> h))+True++Can be chained together to show the dataflow through a series of functions++>>> 3 >! 5 >! (+)+8++-}+infixr 1 >!+(>!) :: a -> (a -> b) -> b+(>!) = (!>)
+ src/Control/Flower/Compose.hs view
@@ -0,0 +1,48 @@+{-|+Module      : Control.Flower.Compose+Description : Directional composition combinators+-}+module Control.Flower.Compose ((<.), (.>)) where++{- $setup+>>> import Control.Flower.Apply.Lazy++>>> let x = 3+>>> let y = 4++>>> let f = (+2)+>>> let g = (*2)+>>> let h = (+)+-}++{-| Right-flowing, left-associative composition++Note that this is the opposite direction from typical composition++>>> (f .> g) x == (g . f) x+True++Can be combined with application combinators++>>> 5 |> (+1) .> (*10) :: Int+60++-}+infixl 9 .>+(.>) :: (a -> b) -> (b -> c) -> a -> c+a .> b =  b . a++{-| Left-flowing, right-associative composition++>>> (g <. f) x == (g . f) x+True++Can be combined with application combinators++>>> (+1) <. (*10) <| 5 :: Int+51++-}+infixr 9 <.+(<.) :: (b -> c) -> (a -> b) -> a -> c+b <. a = b . a
+ src/Control/Flower/Functor.hs view
@@ -0,0 +1,7 @@+module Control.Flower.Functor (+  module Control.Flower.Functor.Lazy,+  module Control.Flower.Functor.Strict+) where++import Control.Flower.Functor.Lazy+import Control.Flower.Functor.Strict
+ src/Control/Flower/Functor/Lazy.hs view
@@ -0,0 +1,78 @@+{-|+Module      : Control.Flower.Functor.Lazy+Description : Lazy functor combinators+-}++module Control.Flower.Functor.Lazy (lift, over, (<$), ($>)) where++import Prelude hiding ((<$))+import Flow ((<|))++-- $setup+-- >>> import Flow ((|>), (<.), (.>))++{-| Rename `fmap` to `lift` for consistency++>>> lift (+1) <| Just 0+Just 1++>>> lift (lift (+1)) [[1,2,3],[4,5,6]]+[[2,3,4],[5,6,7]]++-}+lift :: Functor f => (a -> b) -> f a -> f b+lift = fmap++{-| Alias for `apply`, for readability (especially when teaching)++>>> lift (+1) `over` Just 0+Just 1++>>> Just 0 $> (+1) $> (+2)+Just 3++>>> (*2) <$ ([1,2,3] $> (+1))+[4,6,8]++>>> (+8) .> (*2) <$ Just 0+Just 16++>>> (*3) <. (+8) <$ Just 0+Just 24++-}+over :: (a -> b) -> a -> b+over = (<|)++infixr 4 <$+{-| Operator for `lift` highlighting the direction of data flow++>>> (+1) <$ Just 0+Just 1++>>> (+2) <$ (+1) <$ Just 0+Just 3+++>>> ((*2) <$ [1,2,3]) $> (+1)+[3,5,7]++>>> Just 0 $> (+8) .> (*2)+Just 16++>>> Just 0 $> (*3) <. (+8)+Just 24++-}+(<$) :: Functor f => (a -> b) -> f a -> f b+(<$) = lift++infixl 4 $>+{-| Operator for `lift` highlighting the reversed direction of data flow++>>> Just 0 $> (+1)+Just 1++-}+($>) :: Functor f => f a -> (a -> b) -> f b+($>) = flip lift
+ src/Control/Flower/Functor/Strict.hs view
@@ -0,0 +1,58 @@+{-|+Module      : Control.Flower.Functor.Strict+Description : Strict functor combinators (requires a monad instance)+-}++module Control.Flower.Functor.Strict (+  lift',+  over',+  (<!$),+  ($!>)+) where++import Control.Flower.Apply ((<!))+import Control.Monad ((<$!>))++-- $setup+-- >>> import Flow ((<|))++{- | A strict version of `lift`++>>> lift' (+1) <| Just 0+Just 1++>>> lift' (lift' (+1)) [[1,2,3],[4,5,6]]+[[2,3,4],[5,6,7]]++-}+lift' :: Monad m => (a -> b) -> m a -> m b+lift' = (<$!>)++{- | Alias for `apply'`, for readability (especially when teaching)++>>> lift' (+1) `over'` Just 0+Just 1++-}+over' :: (a -> b) -> a -> b+over' = (<!)++{- | Operator for `lift'` highlighting the direction of data flow++>>> (+1) <!$ Just 0+Just 1++-}+infixr 4 <!$+(<!$) :: Monad f => (a -> b) -> f a -> f b+(<!$) = lift'++{- | Operator for `lift'` highlighting the reversed direction of data flow++>>> Just 0 $!> (+1)+Just 1++-}+infixl 4 $!>+($!>) :: Monad f => f a -> (a -> b) -> f b+($!>) = flip lift'
+ src/Control/Flower/Monad.hs view
@@ -0,0 +1,63 @@+{-|+Module      : Control.Flower.Monad+Description : Combinators for directional monadic mapping+-}+module Control.Flower.Monad (+  (<<$), ($>>),+  (=<<$), ($>>=)+) where++{- $setup+>>> import Control.Flower.Compose++>>> let x = Just 3+>>> let y = Just 4++>>> let f = (+2)+>>> let g = (*2)+>>> let h = (+)+-}++{-| A left-associative operator alias for 'Control.Monad.mapM'++>>> putStrLn <. show <<$ [1,2,3]+1+2+3++-}+infixl 4 <<$+(<<$) :: (Foldable f, Monad m) => (a -> m b) -> f a -> m ()+(<<$) = mapM_++{-| An operator alias for 'Control.Monad.mapM'++>>> [1,2,3] $>> show .> putStrLn+1+2+3++-}+infixr 4 $>>+($>>) :: (Foldable f, Monad m) => f a -> (a -> m b) -> m ()+($>>) = flip mapM_++{-| A left-associative operator alias for 'Control.Monad.mapM'++>>> (\x -> [x+1]) =<<$ [1,2,3]+[[2,3,4]]++-}+infixl 4 =<<$+(=<<$) :: (Traversable t, Monad m) => (a -> m b) -> t a -> m (t b)+(=<<$) = mapM++{-| An operator alias for 'Control.Monad.mapM'++>>> [1,2,3] $>>= \x -> [x+1]+[[2,3,4]]++-}+infixr 4 $>>=+($>>=) :: (Traversable t, Monad m) => t a -> (a -> m b) -> m (t b)+($>>=) = flip mapM
+ test/doctests.hs view
@@ -0,0 +1,19 @@+module Main where++import Test.DocTest++main :: IO ()+main = doctest [ "-isrc"+               , "src/Control/Flower/Apply/Lazy.hs"+               , "src/Control/Flower/Apply/Strict.hs"++               , "src/Control/Flower/Compose.hs"++               , "src/Control/Flower/Functor/Lazy.hs"+               , "src/Control/Flower/Functor/Strict.hs"++               , "src/Control/Flower/Applicative/Lazy.hs"+               , "src/Control/Flower/Applicative/Strict.hs"++               , "src/Control/Flower/Monad.hs"+               ]