packages feed

gambler 0.4.0.0 → 0.4.1.0

raw patch · 30 files changed

+309/−55 lines, 30 filesdep ~hspecPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: hspec

API changes (from Hackage documentation)

+ Fold.Nonempty: repeatedly :: forall x xs result. (forall b. NonemptyFold x b -> xs -> b) -> NonemptyFold x result -> NonemptyFold xs result
+ Fold.Nonempty.Utilities: repeatedly :: forall x xs result. (forall b. NonemptyFold x b -> xs -> b) -> NonemptyFold x result -> NonemptyFold xs result
+ Fold.Pure: repeatedly :: forall x xs result. (forall b. Fold x b -> xs -> b) -> Fold x result -> Fold xs result
+ Fold.Pure.Utilities: repeatedly :: forall x xs result. (forall b. Fold x b -> xs -> b) -> Fold x result -> Fold xs result
+ Fold.Shortcut: Alive :: Will -> b -> Vitality a b
+ Fold.Shortcut: Ambivalent :: Will
+ Fold.Shortcut: Dead :: a -> Vitality a b
+ Fold.Shortcut: Tenacious :: Will
+ Fold.Shortcut: data Vitality a b
+ Fold.Shortcut: data Will
+ Fold.Shortcut: motivate :: ShortcutFold a b -> ShortcutFold a b
+ Fold.Shortcut: premap :: (a -> b) -> ShortcutFold b r -> ShortcutFold a r
+ Fold.Shortcut: repeatedly :: forall x xs result. (forall b. ShortcutFold x b -> xs -> b) -> ShortcutFold x result -> ShortcutFold xs result
+ Fold.Shortcut: type Vitality' a = Vitality a a
+ Fold.Shortcut: withVitality :: ShortcutFold a b -> ShortcutFold a (Vitality' b)
+ Fold.Shortcut.Type: type Vitality' a = Vitality a a
+ Fold.Shortcut.Utilities: motivate :: ShortcutFold a b -> ShortcutFold a b
+ Fold.Shortcut.Utilities: premap :: (a -> b) -> ShortcutFold b r -> ShortcutFold a r
+ Fold.Shortcut.Utilities: repeatedly :: forall x xs result. (forall b. ShortcutFold x b -> xs -> b) -> ShortcutFold x result -> ShortcutFold xs result
+ Fold.Shortcut.Utilities: withVitality :: ShortcutFold a b -> ShortcutFold a (Vitality' b)
+ Fold.ShortcutNonempty: Alive :: Will -> b -> Vitality a b
+ Fold.ShortcutNonempty: Ambivalent :: Will
+ Fold.ShortcutNonempty: Dead :: a -> Vitality a b
+ Fold.ShortcutNonempty: Tenacious :: Will
+ Fold.ShortcutNonempty: data Vitality a b
+ Fold.ShortcutNonempty: data Will
+ Fold.ShortcutNonempty: motivate :: ShortcutNonemptyFold a b -> ShortcutNonemptyFold a b
+ Fold.ShortcutNonempty: premap :: (a -> b) -> ShortcutNonemptyFold b r -> ShortcutNonemptyFold a r
+ Fold.ShortcutNonempty: repeatedly :: forall x xs result. (forall b. ShortcutNonemptyFold x b -> xs -> b) -> ShortcutNonemptyFold x result -> ShortcutNonemptyFold xs result
+ Fold.ShortcutNonempty: type Vitality' a = Vitality a a
+ Fold.ShortcutNonempty: withVitality :: ShortcutNonemptyFold a b -> ShortcutNonemptyFold a (Vitality' b)
+ Fold.ShortcutNonempty.Type: type Vitality' a = Vitality a a
+ Fold.ShortcutNonempty.Utilities: motivate :: ShortcutNonemptyFold a b -> ShortcutNonemptyFold a b
+ Fold.ShortcutNonempty.Utilities: premap :: (a -> b) -> ShortcutNonemptyFold b r -> ShortcutNonemptyFold a r
+ Fold.ShortcutNonempty.Utilities: repeatedly :: forall x xs result. (forall b. ShortcutNonemptyFold x b -> xs -> b) -> ShortcutNonemptyFold x result -> ShortcutNonemptyFold xs result
+ Fold.ShortcutNonempty.Utilities: withVitality :: ShortcutNonemptyFold a b -> ShortcutNonemptyFold a (Vitality' b)

Files

changelog.md view
@@ -1,3 +1,17 @@+## 0.4.1.0 (2023-03-09)++`Will (..)` and `Vitality (..)` are now re-exported from+`Fold.Shortcut` and `Fold.ShortcutNonempty`; previously these+were only available from `Fold.Shortcut.Type` and+`Fold.ShortcutNonempty.Type`.++A new utility `repeatedly` has been added to `Fold.Pure`,+`Fold.Nonempty`, `Fold.Shortcut`, and `Fold.ShortcutNonempty`.++New utilities `motivate`, `premap`, and `withVitality` and a new+type alias `Vitality'` have been added to `Fold.Shortcut` and+`Fold.ShortcutNonempty`.+ ## 0.4.0.0 (2023-03-08)  Changed `ShortcutFold` from
gambler.cabal view
@@ -1,7 +1,7 @@ cabal-version: 3.0  name: gambler-version: 0.4.0.0+version: 0.4.1.0  category: Streaming synopsis: Composable, streaming, and efficient left folds@@ -9,7 +9,7 @@     memory, and you can combine folds using @Applicative@ style to derive new     folds that still traverse the list only once. -author: Gabriella Gonzalez+author: Gabriella Gonzalez, Chris Martin maintainer: Chris Martin, Julie Moronuki  license: BSD-3-Clause
source/Fold.hs view
@@ -73,7 +73,7 @@ effectfulToNonempty = ConvertTo.Nonempty.effectfulFold  {-| Turn a fold that requires at least one input into a fold that returns-'Data.Maybe.Nothing' when there are no inputs -}+    'Data.Maybe.Nothing' when there are no inputs -} nonemptyToEmpty :: NonemptyFold a b -> Fold a (Maybe b) nonemptyToEmpty = ConvertTo.Pure.nonemptyFold @@ -86,7 +86,7 @@ effectfulToPure = ConvertTo.Pure.effectfulFold  {-| Turn a nonempty fold that requires at least one input into a fold that-returns 'Data.Maybe.Nothing' when there are no inputs -}+    returns 'Data.Maybe.Nothing' when there are no inputs -} nonemptyToEffectful :: Monad m =>     NonemptyFold a b -> EffectfulFold m a (Maybe b) nonemptyToEffectful = ConvertTo.Effectful.nonemptyFold@@ -100,16 +100,16 @@ reverseNonemptyList = Nonempty.reverseList  {-| Allows to continue feeding a fold even after passing it to a function-that closes it -}+    that closes it -} duplicateFold :: Fold a b -> Fold a (Fold a b) duplicateFold = Pure.duplicate  {-| Allows to continue feeding a fold even after passing it to a function-that closes it -}+    that closes it -} duplicateNonemptyFold :: NonemptyFold a b -> NonemptyFold a (Fold a b) duplicateNonemptyFold = Nonempty.duplicate  {-| Allows to continue feeding an effectful fold even after passing it to a-function that closes it -}+    function that closes it -} duplicateEffectfulFold :: Applicative m => EffectfulFold m a b -> EffectfulFold m a (EffectfulFold m a b) duplicateEffectfulFold = Effectful.duplicate
source/Fold/Effectful/Conversion.hs view
@@ -22,7 +22,7 @@     }  {-| Turn a nonempty fold that requires at least one input into a fold that-returns 'Data.Maybe.Nothing' when there are no inputs -}+    returns 'Data.Maybe.Nothing' when there are no inputs -} nonemptyFold :: Monad m => NonemptyFold a b -> EffectfulFold m a (Maybe b) nonemptyFold x = fold (Pure.nonemptyFold x) 
source/Fold/Effectful/Examples/Boring.hs view
@@ -32,7 +32,7 @@ import qualified Fold.Effectful.Conversion as Convert  {-| Start with the first input, append each new input on the right-with the given function -}+    with the given function -} magma :: (a -> a -> a) -> Monad m => EffectfulFold m a (Maybe a) magma step = Convert.nonemptyFold (Nonempty.magma step) 
source/Fold/Effectful/Examples/Interesting.hs view
@@ -16,7 +16,7 @@ effect f = effectMonoid (\a -> void (f a))  {-| Performs an action for each input, monoidally combining the results-from all the actions. -}+    from all the actions -} effectMonoid ::  (Monoid w, Monad m) => (a -> m w) -> EffectfulFold m a w effectMonoid act = EffectfulFold     { initial = Applicative.pure mempty
source/Fold/Effectful/Run.hs view
@@ -9,7 +9,7 @@ import qualified Data.Foldable as F  {-| Fold an listlike container to an action that produces a single summary-result -}+    result -} run :: Foldable f => Monad m => EffectfulFold m a b -> f a -> m b run EffectfulFold{ initial, step, extract } as0 = do     x0 <- initial
source/Fold/Effectful/Type.hs view
@@ -9,7 +9,7 @@  import qualified Strict -{- | Processes inputs of type @a@ and results in an effectful value of type @m b@ -}+{-| Processes inputs of type @a@ and results in an effectful value of type @m b@ -} data EffectfulFold m a b = forall x. EffectfulFold     { initial :: m x     , step :: x -> a -> m x
source/Fold/Effectful/Utilities.hs view
@@ -10,7 +10,7 @@ import Prelude ((-))  {-| Shift an effectful fold from one monad to another with a morphism such as-@lift@ or @liftIO@ -}+    @lift@ or @liftIO@ -} hoist :: (forall x . m x -> n x) -> EffectfulFold m a b -> EffectfulFold n a b hoist f EffectfulFold{ initial, step, extract } = EffectfulFold     { initial = f initial@@ -19,7 +19,7 @@     }  {-| Allows to continue feeding an effectful fold even after passing it to a-function that closes it -}+    function that closes it -} duplicate :: Applicative m => EffectfulFold m a b -> EffectfulFold m a (EffectfulFold m a b) duplicate EffectfulFold{ initial, step, extract } = EffectfulFold     { initial
source/Fold/Nonempty.hs view
@@ -17,7 +17,7 @@      {- * Conversion -} fold, effectfulFold, shortcutFold, shortcutNonemptyFold, -    {- * Utilities -} duplicate, premap, nest,+    {- * Utilities -} duplicate, repeatedly, premap, nest,   )   where 
source/Fold/Nonempty/Conversion.hs view
@@ -15,13 +15,13 @@ import qualified Fold.ShortcutNonempty.Type as ShortcutNonempty  {-| Turn a regular fold that allows empty input into a fold that-requires at least one input -}+    requires at least one input -} fold :: Fold a b -> NonemptyFold a b fold Fold{ Fold.initial, Fold.step, Fold.extract } =     NonemptyFold{ initial = step initial, step, extract }  {-| Turn an effectful fold into a pure fold that requires at least-one input -}+    one input -} effectfulFold :: EffectfulFold Identity a b -> NonemptyFold a b effectfulFold x = fold (Fold.Conversion.effectfulFold x) 
source/Fold/Nonempty/Examples/Interesting.hs view
@@ -19,7 +19,7 @@ import qualified Strict  {-| Start with the first input, append each new input on the right-with the given function -}+    with the given function -} magma :: (a -> a -> a) -> NonemptyFold a a magma step = NonemptyFold{ initial = id, step, extract = id } 
source/Fold/Nonempty/Type.hs view
@@ -7,7 +7,7 @@  import qualified Strict -{- | Processes at least one input of type @a@ and results in a value of type @b@ -}+{-| Processes at least one input of type @a@ and results in a value of type @b@ -} data NonemptyFold a b = forall x. NonemptyFold     { initial :: a -> x     , step :: x -> a -> x
source/Fold/Nonempty/Utilities.hs view
@@ -7,15 +7,18 @@ import Fold.Pure.Type (Fold (Fold))  import qualified Fold.Pure.Type as Pure+import qualified Fold.Pure.Utilities as Pure+import qualified Fold.Pure.Run as Pure.Run+import qualified Fold.Nonempty.Conversion as Nonempty  {-| Allows to continue feeding a fold even after passing it to a function-that closes it -}+    that closes it -} duplicate :: NonemptyFold a b -> NonemptyFold a (Fold a b) duplicate NonemptyFold{ initial, step, extract } =     NonemptyFold{ initial, step, extract = \x -> Fold         { Pure.initial = x, Pure.step, Pure.extract } } -{-| @(premap f folder)@ returns a new fold where @f@ is applied at each step -}+{-| Applies a function to each input before processing -} premap :: (a -> b) -> NonemptyFold b r -> NonemptyFold a r premap f NonemptyFold{ initial, step, extract } =     NonemptyFold{ initial = \a -> initial (f a),@@ -25,3 +28,17 @@ nest :: Applicative f => NonemptyFold a b -> NonemptyFold (f a) (f b) nest NonemptyFold{ initial, step, extract } = NonemptyFold     { initial = fmap initial, step = liftA2 step, extract = fmap extract }++{-| Convert a nonempty fold for a single item (@x@) into a+    nonempty fold for nonempty lists of items (@xs@) -}+repeatedly :: forall x xs result.+    (forall b. NonemptyFold x b -> xs -> b)+        -- ^ A witness to the fact that @xs@ is a nonempty list of @x@+    -> NonemptyFold x result+    -> NonemptyFold xs result+repeatedly runXs foldX =+  NonemptyFold+    { initial = runXs (duplicate foldX)+    , step = \f -> runXs (Nonempty.fold (Pure.duplicate f))+    , extract = \f -> Pure.Run.run f []+    }
source/Fold/Pure.hs view
@@ -17,7 +17,7 @@      {- * Conversion -} effectfulFold, nonemptyFold, shortcutFold, shortcutNonemptyFold, -    {- * Utilities -} duplicate, premap, prefilter, predropWhile, drop, nest,+    {- * Utilities -} duplicate, repeatedly, premap, prefilter, predropWhile, drop, nest,   )   where 
source/Fold/Pure/Conversion.hs view
@@ -30,7 +30,7 @@       }  {-| Turn a fold that requires at least one input into a fold that returns-'Data.Maybe.Nothing' when there are no inputs -}+    'Data.Maybe.Nothing' when there are no inputs -} nonemptyFold :: NonemptyFold a b -> Fold a (Maybe b) nonemptyFold   NonemptyFold{ Nonempty.initial, Nonempty.step, Nonempty.extract } =
source/Fold/Pure/Run.hs view
@@ -19,7 +19,7 @@     cons a k x = k $! step x a  {-| Rather than only obtain a single final result, scanning gives a running-total that shows the intermediate result at each step along the way+    total that shows the intermediate result at each step along the way  @ scan 'Fold.Pure.Examples.monoid' ["a", "b", "c"] = ["","a","ab","abc"]
source/Fold/Pure/Type.hs view
@@ -7,7 +7,7 @@  import qualified Strict -{- | Processes inputs of type @a@ and results in a value of type @b@ -}+{-| Processes inputs of type @a@ and results in a value of type @b@ -} data Fold a b = forall x. Fold     { initial :: x     , step :: x -> a -> x
source/Fold/Pure/Utilities.hs view
@@ -5,13 +5,14 @@ import Control.Applicative (Applicative, liftA2, pure) import Data.Bool (Bool (False, True), (&&)) import Data.Functor (fmap)+import Fold.Pure.Run (run) import Numeric.Natural (Natural) import Prelude ((-))  import qualified Strict  {-| Allows to continue feeding a fold even after passing it to a function-that closes it -}+    that closes it -} duplicate :: Fold a b -> Fold a (Fold a b) duplicate Fold{ initial, step, extract } =     Fold{ initial, step, extract = \x -> Fold{ initial = x, step, extract } }@@ -51,3 +52,17 @@ nest :: Applicative f => Fold a b -> Fold (f a) (f b) nest Fold{ initial, step, extract } = Fold     { initial = pure initial, step = liftA2 step, extract = fmap extract }++{-| Convert a fold for a single item (@x@) into a fold for+    lists of items (@xs@) -}+repeatedly :: forall x xs result.+    (forall b. Fold x b -> xs -> b)+        -- ^ A witness to the fact that @xs@ is a list of @x@+    -> Fold x result+    -> Fold xs result+repeatedly runXs foldX =+  Fold+    { initial = run (duplicate foldX) []+    , step = \f -> runXs (duplicate f)+    , extract = \f -> run f []+    }
source/Fold/Shortcut.hs view
@@ -1,6 +1,6 @@ module Fold.Shortcut   (-    {- * Type -} ShortcutFold (..),+    {- * Type -} ShortcutFold (..), Will (..), Vitality (..), Vitality',      {- * Run -} run, @@ -17,7 +17,7 @@      {- * Conversion -} fold, effectfulFold, nonemptyFold, shortcutNonemptyFold, -    {- * Utilities -} demotivate, duplicate,+    {- * Utilities -} motivate, demotivate, duplicate, repeatedly, premap, withVitality,   )   where 
source/Fold/Shortcut/Type.hs view
@@ -1,7 +1,7 @@ module Fold.Shortcut.Type   (     ShortcutFold (..),-    Will (..), Vitality (..),+    Will (..), Vitality (..), Vitality',   )   where @@ -9,13 +9,13 @@ import Data.Functor (Functor, fmap) import Data.Monoid (Monoid, mempty) import Data.Semigroup (Semigroup, (<>))-import Strict (Will (..), Vitality (..))+import Strict (Will (..), Vitality (..), Vitality') import Data.Void (absurd)  import qualified Strict -{- | Processes inputs of type @a@, has the ability to halt midway-     through the stream, and results in a value of type @b@ -}+{-| Processes inputs of type @a@, has the ability to halt midway+    through the stream, and results in a value of type @b@ -} data ShortcutFold a b = forall x y. ShortcutFold     { initial :: Vitality x y     , step :: y -> a -> Vitality x y
source/Fold/Shortcut/Utilities.hs view
@@ -2,10 +2,19 @@  import Fold.Shortcut.Type -import Strict (willSave)+import Fold.Shortcut.Run (run)+import Strict (willSave, willBoost, getVitality')  import qualified Strict +motivate :: ShortcutFold a b -> ShortcutFold a b+motivate ShortcutFold{ initial, step, extract } =+  ShortcutFold+    { initial = willBoost initial+    , step = \x a -> willBoost (step x a)+    , extract+    }+ {-| Causes a shortcut fold to stop once it becomes ambivalent -} demotivate :: ShortcutFold a b -> ShortcutFold a b demotivate ShortcutFold{ initial, step, extract } =@@ -20,7 +29,7 @@     }  {-| Allows to continue feeding a fold even after passing it to a function-that closes it -}+    that closes it -} duplicate :: ShortcutFold a b -> ShortcutFold a (ShortcutFold a b) duplicate ShortcutFold{ initial, step, extract } =   ShortcutFold@@ -28,3 +37,32 @@     , step     , extract = \v -> ShortcutFold{ initial = v, step, extract }     }++withVitality :: ShortcutFold a b -> ShortcutFold a (Vitality' b)+withVitality ShortcutFold{ initial, step, extract } =+  ShortcutFold+    { initial+    , step+    , extract = \v -> let x = extract v in case v of+        Alive w _ -> Alive w x+        Dead _ -> Dead x+    }++{-| Convert a fold for a single item (@x@) into a fold for lists+    of items (@xs@) -}+repeatedly :: forall x xs result.+    (forall b. ShortcutFold x b -> xs -> b)+        -- ^ A witness to the fact that @xs@ is a list of @x@+    -> ShortcutFold x result+    -> ShortcutFold xs result+repeatedly runXs foldX =+  ShortcutFold+    { initial = run (withVitality (duplicate foldX)) []+    , step = \f xs -> runXs (withVitality (duplicate f)) xs+    , extract = \f -> run (getVitality' f) []+    }++{-| Applies a function to each input before processing -}+premap :: (a -> b) -> ShortcutFold b r -> ShortcutFold a r+premap f ShortcutFold{ initial, step, extract } =+    ShortcutFold{ initial, step = \x a -> step x (f a), extract }
source/Fold/ShortcutNonempty.hs view
@@ -1,6 +1,6 @@ module Fold.ShortcutNonempty   (-    {- * Type -} ShortcutNonemptyFold (..),+    {- * Type -} ShortcutNonemptyFold (..), Will (..), Vitality (..), Vitality',      {- * Run -} run, @@ -17,7 +17,7 @@      {- * Conversion -} fold, effectfulFold, nonemptyFold, shortcutFold, -    {- * Utilities -} demotivate, duplicate,+    {- * Utilities -} motivate, demotivate, duplicate, repeatedly, premap, withVitality,   )   where 
source/Fold/ShortcutNonempty/Type.hs view
@@ -1,7 +1,7 @@ module Fold.ShortcutNonempty.Type   (     ShortcutNonemptyFold (..),-    Will (..), Vitality (..),+    Will (..), Vitality (..), Vitality',   )   where @@ -9,13 +9,13 @@ import Data.Functor (Functor, fmap) import Data.Monoid (Monoid, mempty) import Data.Semigroup (Semigroup, (<>))-import Strict (Will (..), Vitality (..))+import Strict (Will (..), Vitality (..), Vitality') import Data.Void (absurd)  import qualified Strict -{- | Processes at least one input of type @a@, has the ability to halt-     midway through the stream, and results in a value of type @b@ -}+{-| Processes at least one input of type @a@, has the ability to halt+    midway through the stream, and results in a value of type @b@ -} data ShortcutNonemptyFold a b = forall x y. ShortcutNonemptyFold     { initial :: a -> Vitality x y     , step :: y -> a -> Vitality x y
source/Fold/ShortcutNonempty/Utilities.hs view
@@ -3,11 +3,22 @@ import Fold.ShortcutNonempty.Type  import Fold.Shortcut.Type (ShortcutFold (ShortcutFold))-import Strict (willSave)+import Strict (willSave, willBoost, getVitality')  import qualified Strict import qualified Fold.Shortcut.Type as Empty+import qualified Fold.Shortcut.Utilities as Empty+import qualified Fold.Shortcut.Run as Empty (run)+import qualified Fold.ShortcutNonempty.Conversion as Nonempty +motivate :: ShortcutNonemptyFold a b -> ShortcutNonemptyFold a b+motivate ShortcutNonemptyFold{ initial, step, extract } =+  ShortcutNonemptyFold+    { initial = \a -> willBoost (initial a)+    , step = \x a -> willBoost (step x a)+    , extract+    }+ {-| Causes a shortcut fold to stop once it becomes ambivalent -} demotivate :: ShortcutNonemptyFold a b -> ShortcutNonemptyFold a b demotivate ShortcutNonemptyFold{ initial, step, extract } =@@ -22,7 +33,7 @@     }  {-| Allows to continue feeding a fold even after passing it to a function-that closes it -}+    that closes it -} duplicate :: ShortcutNonemptyFold a b -> ShortcutNonemptyFold a (ShortcutFold a b) duplicate ShortcutNonemptyFold{ initial, step, extract } =   ShortcutNonemptyFold@@ -30,3 +41,33 @@     , step     , extract = \v -> ShortcutFold{ Empty.initial = v, Empty.step, Empty.extract }     }++withVitality :: ShortcutNonemptyFold a b -> ShortcutNonemptyFold a (Vitality' b)+withVitality ShortcutNonemptyFold{ initial, step, extract } =+  ShortcutNonemptyFold+    { initial+    , step+    , extract = \v -> let x = extract v in case v of+        Alive w _ -> Alive w x+        Dead _ -> Dead x+    }++{-| Convert a nonempty fold for a single item (@x@) into a+    nonempty fold for nonempty lists of items (@xs@) -}+repeatedly :: forall x xs result.+    (forall b. ShortcutNonemptyFold x b -> xs -> b)+        -- ^ A witness to the fact that @xs@ is a nonempty list of @x@+    -> ShortcutNonemptyFold x result+    -> ShortcutNonemptyFold xs result+repeatedly runXs foldX =+  ShortcutNonemptyFold+    { initial = \xs -> runXs (withVitality (duplicate foldX)) xs+    , step = \f xs -> runXs (withVitality (Nonempty.shortcutFold (Empty.duplicate f))) xs+    , extract = \f -> Empty.run (getVitality' f) []+    }++{-| Applies a function to each input before processing -}+premap :: (a -> b) -> ShortcutNonemptyFold b r -> ShortcutNonemptyFold a r+premap f ShortcutNonemptyFold{ initial, step, extract } =+    ShortcutNonemptyFold{ initial = \a -> initial (f a),+        step = \x a -> step x (f a), extract }
source/Strict.hs view
@@ -1,14 +1,15 @@ {-# LANGUAGE StrictData #-} --- | Strict data types for use as internal--- accumulators to achieve constant space usage.+{-| Strict data types for use as internal+    accumulators to achieve constant space usage -} module Strict   (     {- * Maybe -} Maybe (..), lazy, strict,     {- * Either -} Either (..), hush,     {- * Tuples -} Tuple2 (..), Tuple3 (..),-    {- * Shortcut -} Vitality (..), Will (..),-        unlessDead, vitality2, willSave, isAlive, isDead,+    {- * Shortcut -} Vitality (..), Vitality', Will (..),+        unlessDead, vitality2, willSave, willBoost,+        isAlive, isDead, getVitality',   )   where @@ -69,6 +70,12 @@     Alive Ambivalent x -> Dead (Right x)     Alive Tenacious x -> Alive Tenacious x +willBoost :: Vitality a b -> Vitality a b+willBoost v = case v of+    Dead x -> Dead x+    Alive Ambivalent x -> Alive Tenacious x+    Alive Tenacious x -> Alive Tenacious x+ type Vitality' a = Vitality a a  vitality2 :: Vitality a1 b1 -> Vitality a2 b2@@ -83,3 +90,8 @@  isDead :: Vitality a b -> Bool isDead v = case v of { Alive _ _ -> False; Dead _ -> True }++getVitality' :: Vitality' a -> a+getVitality' v = case v of+    Dead x -> x+    Alive _ x -> x
test/Spec/Nonempty.hs view
@@ -4,10 +4,12 @@  import Test.Hspec +import Control.Applicative (liftA2) import Data.Function ((&), flip) import Data.List.NonEmpty (NonEmpty ((:|)))+import Data.Maybe (Maybe (..)) import Positive (Positive)-import Prelude (String, Integer)+import Prelude (String, Integer, (+), odd)  import qualified Data.List as List import qualified Fold.Pure as Pure@@ -48,9 +50,26 @@      describe "duplicate" do         it "lets a fold run in two phases" do-            let a, c :: NonEmpty Integer+            let a :: NonEmpty Integer                 b :: [Integer]                 a = [1..3]                 b = [4..6]-                c = [1..6]-            (sum & duplicate & flip run a & flip Pure.run b) `shouldBe` (List.sum c)+            (sum & duplicate & flip run a & flip Pure.run b)+                `shouldBe` (List.sum a + List.sum b)++    describe "repeatedly" do+        let a, b, c :: NonEmpty Integer+            a = [2, 4]+            b = [10, 12, 5, 7, 8]+            c = [4, 5, 6]+        it "can fold a list of lists" do+            run (repeatedly run maximum) [a, b, c] `shouldBe` 12+        it "works in Applicative combination with another fold" do+            let f = liftA2 (,) (repeatedly run length) length+            run f [a, b, c] `shouldBe` (10, 3)+        it "works in Applicative combination with another 'repeatedly'" do+            let f = liftA2 (,) (repeatedly run (find odd)) (repeatedly run maximum)+            run f [a, b, c] `shouldBe` (Just 5, 12)+        it "works on an Applicative combination" do+            let f = liftA2 (,) (find odd) maximum+            run (repeatedly run f) [a, b, c] `shouldBe` (Just 5, 12)
test/Spec/Pure.hs view
@@ -4,7 +4,7 @@  import Test.Hspec -import Control.Applicative (pure, (<*>))+import Control.Applicative (pure, (<*>), liftA2) import Data.Bool (Bool (..)) import Data.Foldable (traverse_) import Data.Function (id, on, (.), (&), flip)@@ -12,7 +12,7 @@ import Data.Maybe (Maybe (Just, Nothing)) import Data.Monoid (mempty) import Data.Semigroup (Sum (Sum))-import Prelude ((>), String, Integer, (+), (*))+import Prelude ((>), String, Integer, (+), (*), odd)  import qualified Data.Foldable as Foldable import qualified Data.List as List@@ -145,3 +145,21 @@                 b = [4..6]                 c = [1..6]             (sum & duplicate & flip run a & flip run b) `shouldBe` (List.sum c)++    describe "repeatedly" do+        let a, b, c :: [Integer]+            a = [2, 4]+            b = [10, 12, 5, 7, 8]+            c = [4, 5, 6]+            abc = [a, b, c] :: [[Integer]]+        it "can fold a list of lists" do+            run (repeatedly run sum) abc `shouldBe` List.sum (List.concat abc)+        it "works in Applicative combination with another fold" do+            let f = liftA2 (,) (repeatedly run length) length+            run f abc `shouldBe` (10, 3)+        it "works in Applicative combination with another 'repeatedly'" do+            let f = liftA2 (,) (repeatedly run (find odd)) (repeatedly run maximum)+            run f abc `shouldBe` (Just 5, Just 12)+        it "works on an Applicative combination" do+            let f = liftA2 (,) (find odd) maximum+            run (repeatedly run f) abc `shouldBe` (Just 5, Just 12)
test/Spec/Shortcut.hs view
@@ -4,13 +4,13 @@  import Test.Hspec -import Control.Applicative (pure, (<$>), (<*>))+import Control.Applicative (pure, (<$>), (<*>), liftA2) import Data.Bool (Bool (..)) import Data.Function ((&), flip) import Data.List ((++)) import Data.Maybe (Maybe (Just, Nothing)) import Data.Ord (Ord (..))-import Prelude (Integer, undefined)+import Prelude (Integer, undefined, odd)  import qualified Data.Char as Char @@ -96,3 +96,43 @@                 b = undefined                 f = find (>= 10)             (f & duplicate & flip run a & flip run b) `shouldBe` Just 15++    describe "repeatedly" do+        it "can find an item in a list of lists" do+            let a, b, c :: [Integer]+                a = [2, 8, 6]+                b = [12, 4, 5, 16]+                c = [4, 18, 20]+            run (repeatedly run (find odd)) [a, b, c]+                `shouldBe` Just 5+        it "preserves laziness" do+            let a, b, c :: [Integer]+                a = [2, 8, 6]+                b = 12 : 4 : 5 : undefined+                c = undefined+            run (repeatedly run (find odd)) [a, b, c]+                `shouldBe` Just 5+        it "works within an Applicative combination with another 'repeatedly'" do+            let a, b, c :: [Integer]+                a = [2, 8, 6]+                b = 12 : 4 : 5 : undefined+                c = undefined+                f = liftA2 (,) (repeatedly run (find odd)) (repeatedly run (find (> 5)))+            run f [a, b, c]+                `shouldBe` (Just 5, Just 8)+        it "works on an Applicative combination of 'repeatedly's" do+            let a, b, c :: [Integer]+                a = [2, 8, 6]+                b = 12 : 4 : 5 : undefined+                c = undefined+                f = liftA2 (,) (find odd) (find (> 5))+            run (repeatedly run f) [a, b, c]+                `shouldBe` (Just 5, Just 8)+        it "works within an Applicative combination with something ambivalent" do+            let a, b, c :: [Integer]+                a = [2, 8, 6]+                b = 12 : 4 : 5 : undefined+                c = undefined+                f = liftA2 (,) (find odd) length+            run (repeatedly run f) [a, b, c]+                `shouldBe` (Just 5, 6)
test/Spec/ShortcutNonempty.hs view
@@ -12,7 +12,7 @@ import Data.Maybe (Maybe (..)) import Data.Ord (Ord (..)) import Positive (Positive)-import Prelude (Integer, undefined)+import Prelude (Integer, undefined, odd)  import qualified Data.Char as Char import qualified Fold.Shortcut as Empty@@ -83,3 +83,43 @@                 b = undefined                 f = find (>= 10)             (f & duplicate & flip run a & flip Empty.run b) `shouldBe` Just 15++    describe "repeatedly" do+        it "can find an item in a list of lists" do+            let a, b, c :: NonEmpty Integer+                a = [2, 8, 6]+                b = [12, 4, 5, 16]+                c = [4, 18, 20]+            run (repeatedly run (find odd)) [a, b, c]+                `shouldBe` Just 5+        it "preserves laziness" do+            let a, b, c :: NonEmpty Integer+                a = [2, 8, 6]+                b = 12 :| 4 : 5 : undefined+                c = undefined+            run (repeatedly run (find odd)) [a, b, c]+                `shouldBe` Just 5+        it "works within an Applicative combination with another 'repeatedly'" do+            let a, b, c :: NonEmpty Integer+                a = [2, 8, 6]+                b = 12 :| 4 : 5 : undefined+                c = undefined+                f = liftA2 (,) (repeatedly run (find odd)) (repeatedly run (find (> 5)))+            run f [a, b, c]+                `shouldBe` (Just 5, Just 8)+        it "works on an Applicative combination of 'repeatedly's" do+            let a, b, c :: NonEmpty Integer+                a = [2, 8, 6]+                b = 12 :| 4 : 5 : undefined+                c = undefined+                f = liftA2 (,) (find odd) (find (> 5))+            run (repeatedly run f) [a, b, c]+                `shouldBe` (Just 5, Just 8)+        it "works within an Applicative combination with something ambivalent" do+            let a, b, c :: NonEmpty Integer+                a = [2, 8, 6]+                b = 12 :| 4 : 5 : undefined+                c = undefined+                f = liftA2 (,) (find odd) length+            run (repeatedly run f) [a, b, c]+                `shouldBe` (Just 5, 6)