gambler 0.3.0.0 → 0.4.0.0
raw patch · 23 files changed
+211/−127 lines, 23 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Fold.Shortcut: [extractDead] :: ShortcutFold a b -> x -> b
- Fold.Shortcut: [extractLive] :: ShortcutFold a b -> y -> b
- Fold.Shortcut.Type: [extractDead] :: ShortcutFold a b -> x -> b
- Fold.Shortcut.Type: [extractLive] :: ShortcutFold a b -> y -> b
- Fold.ShortcutNonempty: [extractDead] :: ShortcutNonemptyFold a b -> x -> b
- Fold.ShortcutNonempty: [extractLive] :: ShortcutNonemptyFold a b -> y -> b
- Fold.ShortcutNonempty.Type: [extractDead] :: ShortcutNonemptyFold a b -> x -> b
- Fold.ShortcutNonempty.Type: [extractLive] :: ShortcutNonemptyFold a b -> y -> b
+ Fold.Shortcut: [extract] :: ShortcutFold a b -> Vitality x y -> b
+ Fold.Shortcut: duplicate :: ShortcutFold a b -> ShortcutFold a (ShortcutFold a b)
+ Fold.Shortcut.Type: [extract] :: ShortcutFold a b -> Vitality x y -> b
+ Fold.Shortcut.Utilities: duplicate :: ShortcutFold a b -> ShortcutFold a (ShortcutFold a b)
+ Fold.ShortcutNonempty: [extract] :: ShortcutNonemptyFold a b -> Vitality x y -> b
+ Fold.ShortcutNonempty: duplicate :: ShortcutNonemptyFold a b -> ShortcutNonemptyFold a (ShortcutFold a b)
+ Fold.ShortcutNonempty.Type: [extract] :: ShortcutNonemptyFold a b -> Vitality x y -> b
+ Fold.ShortcutNonempty.Utilities: duplicate :: ShortcutNonemptyFold a b -> ShortcutNonemptyFold a (ShortcutFold a b)
- Fold: ShortcutFold :: Vitality x y -> (y -> a -> Vitality x y) -> (x -> b) -> (y -> b) -> ShortcutFold a b
+ Fold: ShortcutFold :: Vitality x y -> (y -> a -> Vitality x y) -> (Vitality x y -> b) -> ShortcutFold a b
- Fold: ShortcutNonemptyFold :: (a -> Vitality x y) -> (y -> a -> Vitality x y) -> (x -> b) -> (y -> b) -> ShortcutNonemptyFold a b
+ Fold: ShortcutNonemptyFold :: (a -> Vitality x y) -> (y -> a -> Vitality x y) -> (Vitality x y -> b) -> ShortcutNonemptyFold a b
- Fold.Shortcut: ShortcutFold :: Vitality x y -> (y -> a -> Vitality x y) -> (x -> b) -> (y -> b) -> ShortcutFold a b
+ Fold.Shortcut: ShortcutFold :: Vitality x y -> (y -> a -> Vitality x y) -> (Vitality x y -> b) -> ShortcutFold a b
- Fold.Shortcut.Type: ShortcutFold :: Vitality x y -> (y -> a -> Vitality x y) -> (x -> b) -> (y -> b) -> ShortcutFold a b
+ Fold.Shortcut.Type: ShortcutFold :: Vitality x y -> (y -> a -> Vitality x y) -> (Vitality x y -> b) -> ShortcutFold a b
- Fold.ShortcutNonempty: ShortcutNonemptyFold :: (a -> Vitality x y) -> (y -> a -> Vitality x y) -> (x -> b) -> (y -> b) -> ShortcutNonemptyFold a b
+ Fold.ShortcutNonempty: ShortcutNonemptyFold :: (a -> Vitality x y) -> (y -> a -> Vitality x y) -> (Vitality x y -> b) -> ShortcutNonemptyFold a b
- Fold.ShortcutNonempty.Type: ShortcutNonemptyFold :: (a -> Vitality x y) -> (y -> a -> Vitality x y) -> (x -> b) -> (y -> b) -> ShortcutNonemptyFold a b
+ Fold.ShortcutNonempty.Type: ShortcutNonemptyFold :: (a -> Vitality x y) -> (y -> a -> Vitality x y) -> (Vitality x y -> b) -> ShortcutNonemptyFold a b
Files
- changelog.md +44/−0
- gambler.cabal +1/−1
- readme.md +6/−10
- source/Fold/Nonempty/Conversion.hs +2/−4
- source/Fold/Pure/Conversion.hs +4/−8
- source/Fold/Shortcut.hs +1/−1
- source/Fold/Shortcut/Conversion.hs +5/−5
- source/Fold/Shortcut/Examples/Interesting.hs +12/−19
- source/Fold/Shortcut/Run.hs +4/−6
- source/Fold/Shortcut/Type.hs +8/−19
- source/Fold/Shortcut/Utilities.hs +16/−5
- source/Fold/ShortcutNonempty.hs +1/−1
- source/Fold/ShortcutNonempty/Conversion.hs +4/−7
- source/Fold/ShortcutNonempty/Examples/Interesting.hs +1/−3
- source/Fold/ShortcutNonempty/Run.hs +4/−6
- source/Fold/ShortcutNonempty/Type.hs +8/−19
- source/Fold/ShortcutNonempty/Utilities.hs +18/−5
- source/Strict.hs +8/−1
- test/Spec/Effectful.hs +1/−1
- test/Spec/Nonempty.hs +13/−0
- test/Spec/Pure.hs +10/−2
- test/Spec/Shortcut.hs +20/−3
- test/Spec/ShortcutNonempty.hs +20/−1
changelog.md view
@@ -1,3 +1,47 @@+## 0.4.0.0 (2023-03-08)++Changed `ShortcutFold` from++```haskell+data ShortcutFold a b = forall x y. ShortcutFold+ { initial :: Vitality x y+ , step :: y -> a -> Vitality x y+ , extractDead :: x -> b+ , extractLive :: y -> b }+```++to++```haskell+data ShortcutFold a b = forall x y. ShortcutFold+ { initial :: Vitality x y+ , step :: y -> a -> Vitality x y+ , extract :: Vitality x y -> b }+```++Changed `ShortcutNonemptyFold` from++```haskell+data ShortcutNonemptyFold a b = forall x y. ShortcutNonemptyFold+ { initial :: a -> Vitality x y+ , step :: y -> a -> Vitality x y+ , extractDead :: x -> b+ , extractLive :: y -> b }+```++to++```haskell+data ShortcutNonemptyFold a b = forall x y. ShortcutNonemptyFold+ { initial :: a -> Vitality x y+ , step :: y -> a -> Vitality x y+ , extract :: Vitality x y -> b }+```++Added `Fold.Shortcut.duplicate` and `Fold.ShortcutNonempty.duplicate`.++(The type changes make the `duplicate` functions possible.)+ ## 0.3.0.0 (2023-03-07) In the `Fold.ShortcutNonempty` module, the type of `list` and
gambler.cabal view
@@ -1,7 +1,7 @@ cabal-version: 3.0 name: gambler-version: 0.3.0.0+version: 0.4.0.0 category: Streaming synopsis: Composable, streaming, and efficient left folds
readme.md view
@@ -176,11 +176,9 @@ ```haskell data ShortcutFold a b = forall x y. ShortcutFold- { initial :: Vitality x y- , step :: y -> a -> Vitality x y- , extractDead :: x -> b- , extractLive :: y -> b- }+ { initial :: Vitality x y+ , step :: y -> a -> Vitality x y+ , extract :: Vitality x y -> b } ``` ```haskell@@ -220,11 +218,9 @@ ```haskell data ShortcutNonemptyFold a b = forall x y. ShortcutNonemptyFold- { initial :: a -> Vitality x y- , step :: y -> a -> Vitality x y- , extractDead :: x -> b- , extractLive :: y -> b- }+ { initial :: a -> Vitality x y+ , step :: y -> a -> Vitality x y+ , extract :: Vitality x y -> b } ``` Like `NonemptyFold`, the only thing we've changed here is to add an `a`
source/Fold/Nonempty/Conversion.hs view
@@ -30,11 +30,9 @@ shortcutNonemptyFold :: ShortcutNonemptyFold a b -> NonemptyFold a b shortcutNonemptyFold ShortcutNonemptyFold{ ShortcutNonempty.step,- ShortcutNonempty.initial, ShortcutNonempty.extractDead, ShortcutNonempty.extractLive } =+ ShortcutNonempty.initial, ShortcutNonempty.extract } = NonemptyFold { initial = initial , step = \s -> case s of { Dead _ -> \_ -> s; Alive _ x -> step x }- , extract = \s -> case s of- Dead x -> extractDead x- Alive _ x -> extractLive x+ , extract = extract }
source/Fold/Pure/Conversion.hs view
@@ -44,25 +44,21 @@ shortcutFold :: ShortcutFold a b -> Fold a b shortcutFold ShortcutFold{- Shortcut.initial, Shortcut.step, Shortcut.extractLive, Shortcut.extractDead } =+ Shortcut.initial, Shortcut.step, Shortcut.extract } = Fold { initial = initial , step = \s -> case s of { Dead _ -> \_ -> s; Alive _ x -> step x }- , extract = \s -> case s of- Dead x -> extractDead x- Alive _ x -> extractLive x+ , extract } shortcutNonemptyFold :: ShortcutNonemptyFold a b -> Fold a (Maybe b) shortcutNonemptyFold ShortcutNonemptyFold{ ShortcutNonempty.initial,- ShortcutNonempty.step, ShortcutNonempty.extractLive, ShortcutNonempty.extractDead } =+ ShortcutNonempty.step, ShortcutNonempty.extract } = Fold { initial = Strict.Nothing , step = \xm a -> case xm of Strict.Nothing -> Strict.Just (initial a) Strict.Just (Alive _ x) -> Strict.Just (step x a) Strict.Just (Dead _) -> xm- , extract = \xm -> Strict.lazy xm <&> \s -> case s of- Dead x -> extractDead x- Alive _ x -> extractLive x+ , extract = \xm -> Strict.lazy xm <&> extract }
source/Fold/Shortcut.hs view
@@ -17,7 +17,7 @@ {- * Conversion -} fold, effectfulFold, nonemptyFold, shortcutNonemptyFold, - {- * Utilities -} demotivate,+ {- * Utilities -} demotivate, duplicate, ) where
source/Fold/Shortcut/Conversion.hs view
@@ -22,8 +22,7 @@ ShortcutFold { initial = Alive Ambivalent initial , step = \x a -> Alive Ambivalent (step x a)- , extractDead = absurd- , extractLive = extract+ , extract = \v -> case v of { Alive _ x -> extract x; Dead x -> absurd x } } effectfulFold :: EffectfulFold Identity a b -> ShortcutFold a b@@ -34,12 +33,13 @@ shortcutNonemptyFold :: ShortcutNonemptyFold a b -> ShortcutFold a (Maybe b) shortcutNonemptyFold ShortcutNonemptyFold{ ShortcutNonempty.initial,- ShortcutNonempty.step, ShortcutNonempty.extractDead, ShortcutNonempty.extractLive } =+ ShortcutNonempty.step, ShortcutNonempty.extract } = ShortcutFold { initial = Alive Tenacious Strict.Nothing , step = \xm a -> Strict.Just <$> case xm of Strict.Nothing -> initial a Strict.Just x -> step x a- , extractDead = \x -> Just (extractDead x)- , extractLive = \xm -> extractLive <$> Strict.lazy xm+ , extract = \v -> case v of+ Dead x -> Just (extract (Dead x))+ Alive w xm -> (\x -> extract (Alive w x)) <$> Strict.lazy xm }
source/Fold/Shortcut/Examples/Interesting.hs view
@@ -10,14 +10,15 @@ import Fold.Shortcut.Type import Control.Applicative (liftA2)-import Data.Bool (Bool (False, True))+import Data.Bool (Bool) import Data.Eq (Eq, (/=), (==)) import Data.Functor (($>), (<&>)) import Data.Maybe (Maybe (Just, Nothing))-import Numeric.Natural (Natural)-import Prelude ((-)) import Fold.Shortcut.Conversion (fold) import Fold.Shortcut.Utilities (demotivate)+import Numeric.Natural (Natural)+import Prelude ((-))+import Strict (isAlive, isDead) import qualified Fold.Pure.Examples.Interesting as Fold @@ -26,8 +27,7 @@ null = ShortcutFold { initial = Alive Tenacious () , step = \() _ -> Dead ()- , extractLive = \() -> True- , extractDead = \() -> False+ , extract = isAlive } {-| 'True' if all inputs are 'True' (tenacious) -}@@ -35,8 +35,7 @@ and = ShortcutFold { initial = Alive Tenacious () , step = \_ a -> if a then Alive Tenacious () else Dead ()- , extractLive = \() -> True- , extractDead = \() -> False+ , extract = isAlive } {-| 'True' if any input is 'True' (tenacious) -}@@ -44,8 +43,7 @@ or = ShortcutFold { initial = Alive Tenacious () , step = \() a -> if a then Dead () else Alive Tenacious ()- , extractLive = \() -> False- , extractDead = \() -> True+ , extract = isDead } {-| 'True' if all inputs satisfy the predicate (tenacious) -}@@ -53,8 +51,7 @@ all predicate = ShortcutFold { initial = Alive Tenacious () , step = \() a -> if predicate a then Alive Tenacious () else Dead ()- , extractLive = \() -> True- , extractDead = \() -> False+ , extract = isAlive } {-| 'True' if any input satisfies the predicate (tenacious) -}@@ -62,8 +59,7 @@ any predicate = ShortcutFold { initial = Alive Tenacious () , step = \_ a -> if predicate a then Dead () else Alive Tenacious ()- , extractLive = \() -> False- , extractDead = \() -> True+ , extract = isDead } {-| 'True' if any input is equal to the given value (tenacious) -}@@ -79,8 +75,7 @@ find ok = ShortcutFold { initial = Alive Tenacious () , step = \() a -> if ok a then Dead a else Alive Tenacious ()- , extractDead = Just- , extractLive = \() -> Nothing+ , extract = \v -> case v of { Dead x -> Just x; _ -> Nothing } } {-| The /n/th input, where n=0 is the first input, if the index is in@@ -89,8 +84,7 @@ index i = ShortcutFold { initial = Alive Tenacious i , step = \i' a -> if i' == 0 then Dead a else Alive Tenacious (i' - 1)- , extractDead = Just- , extractLive = \_ -> Nothing+ , extract = \v -> case v of { Dead x -> Just x; _ -> Nothing } } {-| The index of the first input that matches the given value, if any@@ -113,6 +107,5 @@ lookup a0 = ShortcutFold { initial = Alive Tenacious () , step = \() (a, b) -> if a == a0 then Dead b else Alive Tenacious ()- , extractLive = \() -> Nothing- , extractDead = Just+ , extract = \v -> case v of { Dead x -> Just x; _ -> Nothing } }
source/Fold/Shortcut/Run.hs view
@@ -3,11 +3,9 @@ import Fold.Shortcut.Type {-| Fold a listlike container to a single summary result, forcing- only enough input to satisfy the short-cutting fold -}+ only enough input to satisfy the short-cutting fold's tenacity -} run :: ShortcutFold a b -> [a] -> b-run ShortcutFold{ initial, step, extractDead, extractLive } = go initial+run ShortcutFold{ initial, step, extract } = go initial where- go (Alive Tenacious x) (a : as) = go (step x a) as- go (Alive Tenacious x) [] = extractLive x- go (Alive Ambivalent x) _ = extractLive x- go (Dead x) _ = extractDead x+ go (Alive Tenacious x) (a : as) = go (step x a) as+ go v _ = extract v
source/Fold/Shortcut/Type.hs view
@@ -19,43 +19,32 @@ data ShortcutFold a b = forall x y. ShortcutFold { initial :: Vitality x y , step :: y -> a -> Vitality x y- , extractDead :: x -> b- , extractLive :: y -> b+ , extract :: Vitality x y -> b } instance Functor (ShortcutFold a) where- fmap f ShortcutFold{ step, initial, extractDead, extractLive } =- ShortcutFold- { initial- , step- , extractDead = \x -> f (extractDead x)- , extractLive = \x -> f (extractLive x)- }+ fmap f ShortcutFold{ step, initial, extract } =+ ShortcutFold{ initial, step, extract = \x -> f (extract x) } instance Applicative (ShortcutFold a) where pure b = ShortcutFold { initial = Dead () , step = absurd- , extractDead = \() -> b- , extractLive = absurd+ , extract = \e -> case e of { Dead () -> b } } (<*>)- ShortcutFold{ initial = initialL, step = stepL, extractDead = extractDeadL, extractLive = extractLiveL }- ShortcutFold{ initial = initialR, step = stepR, extractDead = extractDeadR, extractLive = extractLiveR } =+ ShortcutFold{ initial = initialL, step = stepL, extract = extractL }+ ShortcutFold{ initial = initialR, step = stepR, extract = extractR } = ShortcutFold { initial = Strict.vitality2 initialL initialR , step = \(Strict.Tuple2 xL xR) a -> Strict.vitality2 (Strict.unlessDead (\x -> stepL x a) xL) (Strict.unlessDead (\x -> stepR x a) xR)- , extractDead = extract- , extractLive = extract+ , extract = \e -> case e of { Dead x -> ex x; Alive _ x -> ex x } } where- extract(Strict.Tuple2 xL xR) = f x- where- f = case xL of { Dead a -> extractDeadL a; Alive _ b -> extractLiveL b }- x = case xR of { Dead a -> extractDeadR a; Alive _ b -> extractLiveR b }+ ex (Strict.Tuple2 xL xR) = (extractL xL) (extractR xR) instance Semigroup b => Semigroup (ShortcutFold a b) where (<>) = liftA2 (<>)
source/Fold/Shortcut/Utilities.hs view
@@ -8,12 +8,23 @@ {-| Causes a shortcut fold to stop once it becomes ambivalent -} demotivate :: ShortcutFold a b -> ShortcutFold a b-demotivate ShortcutFold{ initial, step, extractDead, extractLive } =+demotivate ShortcutFold{ initial, step, extract } = ShortcutFold { initial = willSave initial , step = \x a -> willSave (step x a)- , extractDead = \e -> case e of- Strict.Left x -> extractDead x- Strict.Right x -> extractLive x- , extractLive = extractLive+ , extract = \v -> case v of+ Dead e -> case e of+ Strict.Left x -> extract (Dead x)+ Strict.Right x -> extract (Alive Ambivalent x)+ Alive w x -> extract (Alive w x)+ }++{-| Allows to continue feeding a fold even after passing it to a function+that closes it -}+duplicate :: ShortcutFold a b -> ShortcutFold a (ShortcutFold a b)+duplicate ShortcutFold{ initial, step, extract } =+ ShortcutFold+ { initial+ , step+ , extract = \v -> ShortcutFold{ initial = v, step, extract } }
source/Fold/ShortcutNonempty.hs view
@@ -17,7 +17,7 @@ {- * Conversion -} fold, effectfulFold, nonemptyFold, shortcutFold, - {- * Utilities -} demotivate,+ {- * Utilities -} demotivate, duplicate, ) where
source/Fold/ShortcutNonempty/Conversion.hs view
@@ -21,8 +21,7 @@ ShortcutNonemptyFold { initial = \a -> Alive Ambivalent (step initial a) , step = \x a -> Alive Ambivalent (step x a)- , extractDead = absurd- , extractLive = extract+ , extract = \v -> case v of { Alive _ x -> extract x; Dead x -> absurd x } } effectfulFold :: EffectfulFold Identity a b -> ShortcutNonemptyFold a b@@ -34,18 +33,16 @@ ShortcutNonemptyFold { initial = \a -> Alive Ambivalent (initial a) , step = \x a -> Alive Ambivalent (step x a)- , extractDead = absurd- , extractLive = extract+ , extract = \v -> case v of { Alive _ x -> extract x; Dead x -> absurd x } } shortcutFold :: ShortcutFold a b -> ShortcutNonemptyFold a b shortcutFold ShortcutFold{ Shortcut.initial, Shortcut.step,- Shortcut.extractDead, Shortcut.extractLive } =+ Shortcut.extract } = ShortcutNonemptyFold { initial = case initial of Dead x -> \_ -> Dead x Alive _ x -> step x , step = step- , extractDead = extractDead- , extractLive = extractLive+ , extract }
source/Fold/ShortcutNonempty/Examples/Interesting.hs view
@@ -6,7 +6,6 @@ import Fold.ShortcutNonempty.Type -import Data.Function (id) import Data.Void (absurd) {-| The first input (tenacious) -}@@ -14,6 +13,5 @@ first = ShortcutNonemptyFold { initial = Dead , step = absurd- , extractDead = id- , extractLive = absurd+ , extract = \v -> case v of { Dead x -> x } }
source/Fold/ShortcutNonempty/Run.hs view
@@ -5,12 +5,10 @@ import Data.List.NonEmpty (NonEmpty ((:|))) {-| Fold a nonempty listlike container to a single summary result,- forcing only enough input to satisfy the short-cutting fold -}+ forcing only enough input to satisfy the short-cutting fold's tenacity -} run :: ShortcutNonemptyFold a b -> NonEmpty a -> b-run ShortcutNonemptyFold{ initial, step, extractDead, extractLive } =+run ShortcutNonemptyFold{ initial, step, extract } = \(z :| as) -> go (initial z) as where- go (Alive Tenacious x) (a : as) = go (step x a) as- go (Alive Tenacious x) [] = extractLive x- go (Alive Ambivalent x) _ = extractLive x- go (Dead x) _ = extractDead x+ go (Alive Tenacious x) (a : as) = go (step x a) as+ go v _ = extract v
source/Fold/ShortcutNonempty/Type.hs view
@@ -19,43 +19,32 @@ data ShortcutNonemptyFold a b = forall x y. ShortcutNonemptyFold { initial :: a -> Vitality x y , step :: y -> a -> Vitality x y- , extractDead :: x -> b- , extractLive :: y -> b+ , extract :: Vitality x y -> b } instance Functor (ShortcutNonemptyFold a) where- fmap f ShortcutNonemptyFold{ step, initial, extractDead, extractLive } =- ShortcutNonemptyFold- { initial- , step- , extractDead = \x -> f (extractDead x)- , extractLive = \x -> f (extractLive x)- }+ fmap f ShortcutNonemptyFold{ step, initial, extract } =+ ShortcutNonemptyFold{ initial, step, extract = \x -> f (extract x) } instance Applicative (ShortcutNonemptyFold a) where pure b = ShortcutNonemptyFold { initial = \_ -> Dead () , step = absurd- , extractDead = \() -> b- , extractLive = absurd+ , extract = \e -> case e of { Dead () -> b } } (<*>)- ShortcutNonemptyFold{ initial = initialL, step = stepL, extractDead = extractDeadL, extractLive = extractLiveL }- ShortcutNonemptyFold{ initial = initialR, step = stepR, extractDead = extractDeadR, extractLive = extractLiveR } =+ ShortcutNonemptyFold{ initial = initialL, step = stepL, extract = extractL }+ ShortcutNonemptyFold{ initial = initialR, step = stepR, extract = extractR } = ShortcutNonemptyFold { initial = \a -> Strict.vitality2 (initialL a) (initialR a) , step = \(Strict.Tuple2 xL xR) a -> Strict.vitality2 (Strict.unlessDead (\x -> stepL x a) xL) (Strict.unlessDead (\x -> stepR x a) xR)- , extractDead = extract- , extractLive = extract+ , extract = \e -> case e of { Dead x -> ex x; Alive _ x -> ex x } } where- extract(Strict.Tuple2 xL xR) = f x- where- f = case xL of { Dead a -> extractDeadL a; Alive _ b -> extractLiveL b }- x = case xR of { Dead a -> extractDeadR a; Alive _ b -> extractLiveR b }+ ex (Strict.Tuple2 xL xR) = (extractL xL) (extractR xR) instance Semigroup b => Semigroup (ShortcutNonemptyFold a b) where (<>) = liftA2 (<>)
source/Fold/ShortcutNonempty/Utilities.hs view
@@ -2,18 +2,31 @@ import Fold.ShortcutNonempty.Type +import Fold.Shortcut.Type (ShortcutFold (ShortcutFold)) import Strict (willSave) import qualified Strict+import qualified Fold.Shortcut.Type as Empty {-| Causes a shortcut fold to stop once it becomes ambivalent -} demotivate :: ShortcutNonemptyFold a b -> ShortcutNonemptyFold a b-demotivate ShortcutNonemptyFold{ initial, step, extractDead, extractLive } =+demotivate ShortcutNonemptyFold{ initial, step, extract } = ShortcutNonemptyFold { initial = \a -> willSave (initial a) , step = \x a -> willSave (step x a)- , extractDead = \e -> case e of- Strict.Left x -> extractDead x- Strict.Right x -> extractLive x- , extractLive = extractLive+ , extract = \v -> case v of+ Dead e -> case e of+ Strict.Left x -> extract (Dead x)+ Strict.Right x -> extract (Alive Ambivalent x)+ Alive w x -> extract (Alive w x)+ }++{-| Allows to continue feeding a fold even after passing it to a function+that closes it -}+duplicate :: ShortcutNonemptyFold a b -> ShortcutNonemptyFold a (ShortcutFold a b)+duplicate ShortcutNonemptyFold{ initial, step, extract } =+ ShortcutNonemptyFold+ { initial+ , step+ , extract = \v -> ShortcutFold{ Empty.initial = v, Empty.step, Empty.extract } }
source/Strict.hs view
@@ -8,10 +8,11 @@ {- * Either -} Either (..), hush, {- * Tuples -} Tuple2 (..), Tuple3 (..), {- * Shortcut -} Vitality (..), Will (..),- unlessDead, vitality2, willSave,+ unlessDead, vitality2, willSave, isAlive, isDead, ) where +import Data.Bool (Bool (..)) import Data.Functor (Functor (..)) import Data.Monoid (Monoid, mempty) import Data.Semigroup (Semigroup, (<>))@@ -76,3 +77,9 @@ vitality2 a@(Dead _) b@(Alive v _) = Alive v (Strict.Tuple2 a b) vitality2 a@(Alive v _) b@(Dead _) = Alive v (Strict.Tuple2 a b) vitality2 a@(Dead _) b@(Dead _) = Dead (Strict.Tuple2 a b)++isAlive :: Vitality a b -> Bool+isAlive v = case v of { Alive _ _ -> True; Dead _ -> False }++isDead :: Vitality a b -> Bool+isDead v = case v of { Alive _ _ -> False; Dead _ -> True }
test/Spec/Effectful.hs view
@@ -6,6 +6,7 @@ import Control.Applicative (pure, (<*>)) import Control.Monad ((<=<))+import Data.Bool (Bool (..)) import Data.Foldable (traverse_) import Data.Function (id, on, (.), (&)) import Data.Functor ((<$>))@@ -13,7 +14,6 @@ import Data.Monoid (mempty) import Data.Semigroup (Sum (Sum), (<>)) import Prelude ((>), String, Integer, (+), (*))-import Data.Bool (Bool (..)) import qualified Data.List as List
test/Spec/Nonempty.hs view
@@ -4,10 +4,14 @@ import Test.Hspec +import Data.Function ((&), flip) import Data.List.NonEmpty (NonEmpty ((:|))) import Positive (Positive) import Prelude (String, Integer) +import qualified Data.List as List+import qualified Fold.Pure as Pure+ spec :: SpecWith () spec = describe "NonemptyFold" do @@ -41,3 +45,12 @@ run sum [1,2,5] `shouldBe` (8 :: Positive) it "product works with Positive" do run product [1,2,5] `shouldBe` (10 :: Positive)++ describe "duplicate" do+ it "lets a fold run in two phases" do+ let a, c :: 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)
test/Spec/Pure.hs view
@@ -5,14 +5,14 @@ import Test.Hspec import Control.Applicative (pure, (<*>))+import Data.Bool (Bool (..)) import Data.Foldable (traverse_)-import Data.Function (id, on, (.), (&))+import Data.Function (id, on, (.), (&), flip) import Data.Functor ((<$>)) import Data.Maybe (Maybe (Just, Nothing)) import Data.Monoid (mempty) import Data.Semigroup (Sum (Sum)) import Prelude ((>), String, Integer, (+), (*))-import Data.Bool (Bool (..)) import qualified Data.Foldable as Foldable import qualified Data.List as List@@ -137,3 +137,11 @@ run null ([1] :: [Integer]) `shouldBe` False run null ([1,2] :: [Integer]) `shouldBe` False run null ([1,2,3] :: [Integer]) `shouldBe` False++ describe "duplicate" do+ it "lets a fold run in two phases" do+ let a, b, c :: [Integer]+ a = [1..3]+ b = [4..6]+ c = [1..6]+ (sum & duplicate & flip run a & flip run b) `shouldBe` (List.sum c)
test/Spec/Shortcut.hs view
@@ -5,10 +5,12 @@ import Test.Hspec import Control.Applicative (pure, (<$>), (<*>))-import Prelude (Integer, undefined)-import Data.Maybe (Maybe (Just, Nothing))-import Data.List ((++)) 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 qualified Data.Char as Char @@ -79,3 +81,18 @@ run or [True,False] `shouldBe` True it "is lazy" do run or (True : undefined) `shouldBe` True++ describe "duplicate" do+ it "lets a fold run in two phases" do+ let a, b, c :: [Integer]+ a = [1,2,3]+ b = [4,7,12,15]+ c = a ++ b+ f = find (>= 10)+ (f & duplicate & flip run a & flip run b) `shouldBe` (run f c)+ it "preserves laziness" do+ let a, b :: [Integer]+ a = 1 : 15 : undefined+ b = undefined+ f = find (>= 10)+ (f & duplicate & flip run a & flip run b) `shouldBe` Just 15
test/Spec/ShortcutNonempty.hs view
@@ -6,13 +6,16 @@ import Control.Applicative (pure, (<$>), (<*>), liftA2) import Data.Bool (Bool (..))+import Data.Function ((&), flip) import Data.List ((++)) import Data.List.NonEmpty (NonEmpty ((:|)))-import Data.Maybe (Maybe (Just))+import Data.Maybe (Maybe (..))+import Data.Ord (Ord (..)) import Positive (Positive) import Prelude (Integer, undefined) import qualified Data.Char as Char+import qualified Fold.Shortcut as Empty spec :: SpecWith () spec = describe "ShortcutNonemptyFold" do@@ -64,3 +67,19 @@ run (liftA2 (,) (index 2) sum) [1,2,5,7] `shouldBe` (Just 5, 8 :: Positive) it "product works with Positive" do run (liftA2 (,) (index 2) product) [1,2,5,3] `shouldBe` (Just 5, 10 :: Positive)++ describe "duplicate" do+ it "lets a fold run in two phases" do+ let a :: NonEmpty Integer+ b :: [Integer]+ a = [1,2,3]+ b = [4,7,12,15]+ f = find (>= 10)+ (f & duplicate & flip run a & flip Empty.run b) `shouldBe` Just 12+ it "preserves laziness" do+ let a :: NonEmpty Integer+ b :: [Integer]+ a = 1 :| 15 : undefined+ b = undefined+ f = find (>= 10)+ (f & duplicate & flip run a & flip Empty.run b) `shouldBe` Just 15