packages feed

parameterized 0.1.0.0 → 0.2.0.0

raw patch · 11 files changed

+385/−23 lines, 11 filesdep +hspecdep +parameterizeddep ~basedep ~data-diverse

Dependencies added: hspec, parameterized

Dependency ranges changed: base, data-diverse

Files

README.md view
@@ -8,3 +8,8 @@ * 0.1.0.0   - Initial version with parameterized Semigroup, Monoid, Applicative, Alternative, Monad   - Added instances for OverlappingWhichReader, DistinctWhichReader, ManyReader, ManyState, and ChangingState++* 0.2.0.0+  - Renamed Pempty to PEmpty.+  - Added injective functional dependencies to PEmpty, and PEmpty.+  - TypeLevel is not exported by default
parameterized.cabal view
@@ -1,5 +1,5 @@ name:                parameterized-version:             0.1.0.0+version:             0.2.0.0 synopsis:            Extensible records and polymorphic variants. description:         Parameterized/indexed monoids and monads using only a single parameter type variable. @@ -25,9 +25,23 @@                        Parameterized.Control.Monad.Trans.Reader                        Parameterized.Control.Monad.Trans.State.Strict   build-depends:       base >= 4.7 && < 5-                     , data-diverse >= 1.2.0.2+                     , data-diverse >= 1.2.0.3                      , transformers >= 0.5.2.0   ghc-options:         -Wall+  default-language:    Haskell2010++test-suite parameterized-test+  type:                exitcode-stdio-1.0+  hs-source-dirs:      test+  main-is:             Spec.hs+  other-modules:       Parameterized.Control.Monad.Trans.Reader.ReaderSpec+                       Parameterized.Control.Monad.Trans.State.Strict.StateSpec+  build-depends:       base+                     , parameterized+                     , hspec >= 2+                     , data-diverse >= 1.2.0.3+                     , transformers >= 0.5.2.0+  ghc-options:         -threaded -rtsopts -with-rtsopts=-N -Wall   default-language:    Haskell2010  source-repository head
src/Parameterized/Control/Applicative.hs view
@@ -5,8 +5,7 @@ {-# LANGUAGE PolyKinds #-}  module Parameterized.Control.Applicative-    ( module Parameterized.TypeLevel-    , PPointed(..)+    ( PPointed(..)     , PApplicative(..)     , (&<*>)     , (&*>)@@ -20,7 +19,6 @@     ) where  import Data.Kind-import Parameterized.TypeLevel  -- | Parameterized version of 'pure' in 'Applicative' -- An instance of this should create a parameterized unary type@@ -71,7 +69,7 @@ -- | Parameterized version of empty in 'Alternative'. -- An instance of this should create a parameterized unary type -- where the parameter is an identity in respect to 'pappend'-class PEmpty (m :: k -> Type -> Type) (id :: k) where+class PEmpty (m :: k -> Type -> Type) (id :: k) | m -> id where     -- | The identity of '&<|>'     pempty :: m id a 
src/Parameterized/Control/Monad.hs view
@@ -15,7 +15,6 @@     ) where  import Data.Kind-import Parameterized.TypeLevel import Parameterized.Control.Applicative  -- | Parameterized version of Monad.
src/Parameterized/Control/Monad/Trans/Reader.hs view
@@ -63,6 +63,10 @@ -- | Given a Reader that accepts @Which a@, and another Reader that accepts @Which b@ -- make a reader that accepts @Which (Append a b)@ and only run one of the readers for the correct Which type, -- with a compile-time contraint that the types in @Which a@ are distinct from the type in @Which b@+-- The advantage of 'DistinctWhichReader' over 'OverlappingWhichReader' is that 'pappend' doesn't+-- require the inner monad @m@ to be an 'Alternative'.+-- NB. 'PEmpty' still requires 'Alternative' but you don't need to be an instance of 'PEmpty'+-- (analogous to Semigroup) newtype DistinctWhichReader m r a = DistinctWhichReader     { runDistinctWhichReader :: ReaderT r m a     } deriving ( G.Generic
src/Parameterized/Control/Monad/Trans/State/Strict.hs view
@@ -20,6 +20,7 @@ import Data.Diverse import qualified GHC.Generics as G import Parameterized.Control.Monad+import Parameterized.TypeLevel  -- | Given a ManyState that modifies @Many a@, and another ManyState that modifes @Many b@ -- make a State that accepts @Many (AppendUnique a b)@
src/Parameterized/Data/Monoid.hs view
@@ -6,19 +6,17 @@ {-# LANGUAGE PolyKinds #-}  module Parameterized.Data.Monoid-    ( module Parameterized.TypeLevel-    , module Parameterized.Data.Semigroup-    , PMempty(..)+    ( module Parameterized.Data.Semigroup+    , PMEmpty(..)     , PMonoid     ) where  import Data.Kind-import Parameterized.TypeLevel import Parameterized.Data.Semigroup  -- | Parameterized version of mempty in Monoid.-class PMempty (n :: k -> Type) (id :: k) where+class PMEmpty (n :: k -> Type) (id :: k) | n -> id where     pmempty :: n id  -- | Parameterized version of Monoid.-type PMonoid n id t u v = (PMempty n id, PSemigroup n t u v)+type PMonoid n id t u v = (PMEmpty n id, PSemigroup n t u v)
src/Parameterized/TypeLevel.hs view
@@ -6,7 +6,7 @@  module Parameterized.TypeLevel where --- | Get the first type of a type level tuple+-- | Get the first type of a value level tuple -- This is useful for defining a newtype wrapper with a single "parameterized" type, -- around a type with many "parameterized" type variables. type family At0 t where@@ -20,7 +20,7 @@     At0 (x, _, _, _, _, _, _, _, _) = x     At0 (x, _, _, _, _, _, _, _, _, _) = x --- | Get the second type of a type level tuple+-- | Get the second type of a value level tuple type family At1 t where     At1 (_, x) = x     At1 (_, x, _) = x@@ -32,7 +32,7 @@     At1 (_, x, _, _, _, _, _, _, _) = x     At1 (_, x, _, _, _, _, _, _, _, _) = x --- | Get the third type of a type level tuple+-- | Get the third type of a value level tuple type family At2 t where     At2 (_, _, x) = x     At2 (_, _, x, _) = x@@ -43,7 +43,7 @@     At2 (_, _, x, _, _, _, _, _, _) = x     At2 (_, _, x, _, _, _, _, _, _, _) = x --- | Get the fourth type of a type level tuple+-- | Get the fourth type of a value level tuple type family At3 t where     At3 (_, _, _, x) = x     At3 (_, _, _, x, _) = x@@ -53,7 +53,7 @@     At3 (_, _, _, x, _, _, _, _, _) = x     At3 (_, _, _, x, _, _, _, _, _, _) = x --- | Get the fifth type of a type level tuple+-- | Get the fifth type of a value level tuple type family At4 t where     At4 (_, _, _, _, x) = x     At4 (_, _, _, _, x, _) = x@@ -62,7 +62,7 @@     At4 (_, _, _, _, x, _, _, _, _) = x     At4 (_, _, _, _, x, _, _, _, _, _) = x --- | Get the sixth type of a type level tuple+-- | Get the sixth type of a value level tuple type family At5 t where     At5 (_, _, _, _, _, x) = x     At5 (_, _, _, _, _, x, _) = x@@ -70,24 +70,24 @@     At5 (_, _, _, _, _, x, _, _, _) = x     At5 (_, _, _, _, _, x, _, _, _, _) = x --- | Get the seventh type of a type level tuple+-- | Get the seventh type of a value level tuple type family At6 t where     At6 (_, _, _, _, _, _, x) = x     At6 (_, _, _, _, _, _, x, _) = x     At6 (_, _, _, _, _, _, x, _, _) = x     At6 (_, _, _, _, _, _, x, _, _, _) = x --- | Get the eigth type of a type level tuple+-- | Get the eigth type of a value level tuple type family At7 t where     At7 (_, _, _, _, _, _, _, x) = x     At7 (_, _, _, _, _, _, _, x, _) = x     At7 (_, _, _, _, _, _, _, x, _, _) = x --- | Get the nineth type of a type level tuple+-- | Get the nineth type of a value level tuple type family At8 t where     At8 (_, _, _, _, _, _, _, _, x) = x     At8 (_, _, _, _, _, _, _, _, x, _) = x --- | Get the tenth type of a type level tuple+-- | Get the tenth type of a value level tuple type family At9 t where     At9 (_, _, _, _, _, _, _, _, _, x) = x
+ test/Parameterized/Control/Monad/Trans/Reader/ReaderSpec.hs view
@@ -0,0 +1,247 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE TypeApplications #-}++module Parameterized.Control.Monad.Trans.Reader.ReaderSpec (main, spec) where++import Control.Applicative+import Control.Monad.Trans.Reader+import Parameterized.Control.Monad.Trans.Reader+import Parameterized.Control.Monad+import Data.Diverse+import Data.Semigroup+import Test.Hspec+++-- `main` is here so that this module can be run from GHCi on its own.  It is+-- not needed for automatic spec dicovery.+main :: IO ()+main = hspec spec++whichIntMaybeReader :: ReaderT (Which '[Int]) Maybe String+whichIntMaybeReader = do+    a <- ask+    pure . show $ obvious a++whichBoolMaybeReader :: ReaderT (Which '[Bool]) Maybe String+whichBoolMaybeReader = do+    a <- ask+    pure . show $ obvious a++whichStringMaybeReader :: ReaderT (Which '[String]) Maybe String+whichStringMaybeReader = do+    a <- ask+    pure . show $ obvious a++whichIntBoolMaybeReader :: ReaderT (Which '[Int, Bool]) Maybe String+whichIntBoolMaybeReader = do+    ay <- ask+    pure $ switch ay (CaseFunc @Show show)++whichBoolStringMaybeReader :: ReaderT (Which '[Bool, String]) Maybe String+whichBoolStringMaybeReader = do+    ay <- ask+    pure $ switch ay (CaseFunc @Show show)++whichIntStringMaybeReader :: ReaderT (Which '[Int, String]) Maybe String+whichIntStringMaybeReader = do+    ay <- ask+    pure $ switch ay (CaseFunc @Show show)+++whichIntBoolStringMaybeReader :: ReaderT (Which '[Int, Bool, String]) Maybe String+whichIntBoolStringMaybeReader = do+    ay <- ask+    pure $ switch ay (CaseFunc @Show show)++--------------------------------++whichIntReader :: Reader (Which '[Int]) String+whichIntReader = do+    a <- ask+    pure . show $ obvious a++whichBoolReader :: Reader (Which '[Bool]) String+whichBoolReader = do+    a <- ask+    pure . show $ obvious a++whichStringReader :: Reader (Which '[String]) String+whichStringReader = do+    a <- ask+    pure . show $ obvious a++whichIntBoolReader :: Reader (Which '[Int, Bool]) String+whichIntBoolReader = do+    ay <- ask+    pure $ switch ay (CaseFunc @Show show)++whichIntStringReader :: Reader (Which '[Int, String]) String+whichIntStringReader = do+    ay <- ask+    pure $ switch ay (CaseFunc @Show show)+++whichIntBoolStringReader :: Reader (Which '[Int, Bool, String]) String+whichIntBoolStringReader = do+    ay <- ask+    pure $ switch ay (CaseFunc @Show show)++--------------------------------++manyIntMaybeReader :: ReaderT (Many '[Int]) Maybe String+manyIntMaybeReader = do+    a <- ask+    let r = fetch @Int a+    case r of+        0 -> empty+        r' -> pure $ show r'++manyBoolMaybeReader :: ReaderT (Many '[Bool]) Maybe String+manyBoolMaybeReader = do+    a <- ask+    let r = fetch @Bool a+    case r of+        False -> empty+        r' -> pure $ show r'++--------------------------------++spec :: Spec+spec = do+    describe "Reader (Which a)" $ do++        it "is can maybe read only the types it knows about" $ do+            runReaderT whichIntMaybeReader (pick (5 :: Int)) `shouldBe` Just "5"+            runReaderT whichIntBoolMaybeReader (pick (5 :: Int)) `shouldBe` Just "5"+            runReaderT whichIntBoolStringMaybeReader (pick (5 :: Int)) `shouldBe` Just "5"+            runReaderT whichBoolMaybeReader (pick False) `shouldBe` Just "False"+            runReaderT whichIntBoolMaybeReader (pick False) `shouldBe` Just "False"+            runReaderT whichIntBoolStringMaybeReader (pick False) `shouldBe` Just "False"+            runReaderT whichStringMaybeReader (pick "foo") `shouldBe` Just "\"foo\""+            runReaderT whichIntStringMaybeReader (pick "foo") `shouldBe` Just "\"foo\""+            runReaderT whichIntBoolStringMaybeReader (pick "foo") `shouldBe` Just "\"foo\""++        it "is can read only the types it knows about" $ do+            runReader whichIntReader (pick (5 :: Int)) `shouldBe` "5"+            runReader whichIntBoolReader (pick (5 :: Int)) `shouldBe` "5"+            runReader whichIntBoolStringReader (pick (5 :: Int)) `shouldBe` "5"+            runReader whichBoolReader (pick False) `shouldBe` "False"+            runReader whichIntBoolReader (pick False) `shouldBe` "False"+            runReader whichIntBoolStringReader (pick False) `shouldBe` "False"+            runReader whichStringReader (pick "foo") `shouldBe` "\"foo\""+            runReader whichIntStringReader (pick "foo") `shouldBe` "\"foo\""+            runReader whichIntBoolStringReader (pick "foo") `shouldBe` "\"foo\""++    describe "OverlappingWhichReader" $ do+        it "pappend with empty doesn't change the type of the parameter" $ do+            let r1 = OverlappingWhichReader whichIntMaybeReader `pappend` pempty+                r2 = pempty `pappend` OverlappingWhichReader whichIntMaybeReader+                -- the "parameter" doesn't change when `pappend` with empty+                r1' = runOverlappingWhichReader r1 :: ReaderT (Which '[Int]) Maybe String+                r2' = runOverlappingWhichReader r2 :: ReaderT (Which '[Int]) Maybe String+            -- functionality unchanged+            runReaderT r1' (pick (5 :: Int)) `shouldBe` Just "5"+            runReaderT r2' (pick (5 :: Int)) `shouldBe` Just "5"++        it "it can be pappended to combine distinct readers" $ do+            let r = OverlappingWhichReader whichIntMaybeReader `pappend`+                        OverlappingWhichReader whichBoolMaybeReader+                -- the "parameter" is combined+                r' = runOverlappingWhichReader r :: ReaderT (Which '[Int, Bool]) Maybe String+            -- functionality of both readers+            runReaderT r' (pick (5 :: Int)) `shouldBe` Just "5"+            runReaderT r' (pick False) `shouldBe` Just "False"++            let r2 = r `pappend` OverlappingWhichReader whichStringMaybeReader+                -- the "parameter" is combined+                r2' = runOverlappingWhichReader r2 :: ReaderT (Which '[Int, Bool, String]) Maybe String+            -- functionality of both readers+            runReaderT r2' (pick (5 :: Int)) `shouldBe` Just "5"+            runReaderT r2' (pick False) `shouldBe` Just "False"+            runReaderT r2' (pick "foo") `shouldBe` Just "\"foo\""++        it "it can be pappended to combine overlapping readers" $ do+            let r = OverlappingWhichReader whichIntBoolMaybeReader `pappend`+                        OverlappingWhichReader whichBoolStringMaybeReader+                -- the "parameter" is combined+                r' = runOverlappingWhichReader r :: ReaderT (Which '[Int, Bool, String]) Maybe String+            -- functionality of both readers+            runReaderT r' (pick (5 :: Int)) `shouldBe` Just "5"+            runReaderT r' (pick False) `shouldBe` Just "False"+            runReaderT r' (pick "foo") `shouldBe` Just "\"foo\""++    describe "DistinctWhichReader" $ do+        it "pappend with empty doesn't change the type of the parameter" $ do+            let r1 = DistinctWhichReader whichIntMaybeReader `pappend` pempty+                r2 = pempty `pappend` DistinctWhichReader whichIntMaybeReader+                -- the "parameter" doesn't change when `pappend` with empty+                r1' = runDistinctWhichReader r1 :: ReaderT (Which '[Int]) Maybe String+                r2' = runDistinctWhichReader r2 :: ReaderT (Which '[Int]) Maybe String+            -- functionality unchanged+            runReaderT r1' (pick (5 :: Int)) `shouldBe` Just "5"+            runReaderT r2' (pick (5 :: Int)) `shouldBe` Just "5"++        it "it can be pappended to combine distinct readers" $ do+            let r = DistinctWhichReader whichIntReader `pappend` DistinctWhichReader whichBoolReader+                -- the "parameter" is combined+                r' = runDistinctWhichReader r :: Reader (Which '[Int, Bool]) String+            -- functionality of both readers+            runReader r' (pick (5 :: Int)) `shouldBe` "5"+            runReader r' (pick False) `shouldBe` "False"++            let r2 = r `pappend` DistinctWhichReader whichStringReader+                -- the "parameter" is combined+                r2' = runDistinctWhichReader r2 :: Reader (Which '[Int, Bool, String]) String+            -- functionality of both readers+            runReader r2' (pick (5 :: Int)) `shouldBe` "5"+            runReader r2' (pick False) `shouldBe` "False"+            runReader r2' (pick "foo") `shouldBe` "\"foo\""++    describe "ManyReader" $ do+        it "pappend with empty doesn't change the type of the parameter" $ do+            let r1 = ManyReader manyIntMaybeReader `pappend` pempty+                r2 = pempty `pappend` ManyReader manyIntMaybeReader+                -- the "parameter" doesn't change when `pappend` with empty+                r1' = runManyReader r1 :: ReaderT (Many '[Int]) Maybe String+                r2' = runManyReader r2 :: ReaderT (Many '[Int]) Maybe String+            -- functionality unchanged+            runReaderT r1' (single (5 :: Int)) `shouldBe` Just "5"+            runReaderT r2' (single (5 :: Int)) `shouldBe` Just "5"++        it "it can 'pappend' to combine state runners 'Alternative'ly" $ do+            let r = ManyReader manyIntMaybeReader `pappend`+                        ManyReader manyBoolMaybeReader+                -- the "parameter" is combined+                r' = runManyReader r :: ReaderT (Many '[Int, Bool]) Maybe String+            -- functionality of both readers in an Alternative fashion+            runReaderT r' ( (5 :: Int) ./ True ./ nil) `shouldBe` Just "5"+            runReaderT r' ( (5 :: Int) ./ False ./ nil) `shouldBe` Just "5"+            runReaderT r' ( (0 :: Int) ./ True ./ nil) `shouldBe` Just "True"+            runReaderT r' ( (0 :: Int) ./ False ./ nil) `shouldBe` Nothing++        it "it can 'papply' to combine state runners 'Applicative'ly" $ do+            let r = (\a b -> a <> "." <> b) <$> ManyReader manyIntMaybeReader &<*>+                        ManyReader manyBoolMaybeReader+                -- the "parameter" is combined+                r' = runManyReader r :: ReaderT (Many '[Int, Bool]) Maybe String+            -- functionality of both readers in an Alternative fashion+            runReaderT r' ( (5 :: Int) ./ True ./ nil) `shouldBe` Just "5.True"+            runReaderT r' ( (5 :: Int) ./ False ./ nil) `shouldBe` Nothing+            runReaderT r' ( (0 :: Int) ./ True ./ nil) `shouldBe` Nothing+            runReaderT r' ( (0 :: Int) ./ False ./ nil) `shouldBe` Nothing+++        it "it can 'pbind' to combine reader runners 'Monad'ically" $ do+            let r = ManyReader manyIntMaybeReader &>>= \a ->+                        case a of+                            "1" -> ManyReader manyBoolMaybeReader+                            _ -> empty+                -- the "parameter" is combined+                r' = runManyReader r :: ReaderT (Many '[Int, Bool]) Maybe String+            -- functionality of both readers in an Applicative fashion+            runReaderT r' ( (1 :: Int) ./ True ./ nil) `shouldBe` Just "True"+            runReaderT r' ( (1 :: Int) ./ False ./ nil) `shouldBe` Nothing+            runReaderT r' ( (5 :: Int) ./ True ./ nil) `shouldBe` Nothing+            runReaderT r' ( (5 :: Int) ./ False ./ nil) `shouldBe` Nothing+            runReaderT r' ( (0 :: Int) ./ True ./ nil) `shouldBe` Nothing+            runReaderT r' ( (0 :: Int) ./ False ./ nil) `shouldBe` Nothing
+ test/Parameterized/Control/Monad/Trans/State/Strict/StateSpec.hs view
@@ -0,0 +1,95 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE TypeApplications #-}++module Parameterized.Control.Monad.Trans.State.Strict.StateSpec (main, spec) where++import Control.Applicative+import Control.Monad.Trans.State.Strict+import Parameterized.Control.Monad.Trans.State.Strict+import Parameterized.Control.Monad+import Data.Diverse+import Data.Semigroup+import Test.Hspec+++-- `main` is here so that this module can be run from GHCi on its own.  It is+-- not needed for automatic spec dicovery.+main :: IO ()+main = hspec spec++manyIntMaybeState :: StateT (Many '[Int]) Maybe String+manyIntMaybeState= do+    s <- get+    let r = fetch @Int s+    case r of+        0 -> empty+        r' -> do+           put $ replace @Int s (r' + 1)+           pure $ show r'++manyBoolMaybeState :: StateT (Many '[Bool]) Maybe String+manyBoolMaybeState = do+    s <- get+    let r = fetch @Bool s+    case r of+        False -> empty+        r' -> do+            put $ replace @Bool s False+            pure $ show r'++--------------------------------++spec :: Spec+spec = do++    describe "ManyState" $ do+        it "pappend with empty doesn't change the type of the parameter" $ do+            let r1 = ManyState manyIntMaybeState `pappend` pempty+                r2 = pempty `pappend` ManyState manyIntMaybeState+                -- the "parameter" doesn't change when `pappend` with empty+                r1' = runManyState r1 :: StateT (Many '[Int]) Maybe String+                r2' = runManyState r2 :: StateT (Many '[Int]) Maybe String+            -- functionality unchanged+            runStateT r1' (single (5 :: Int)) `shouldBe` Just ("5", single (6 :: Int))+            runStateT r2' (single (5 :: Int)) `shouldBe` Just ("5", single (6 :: Int))++        it "it can 'pappend' to combine state runners 'Alternative'ly" $ do+            let r = ManyState manyIntMaybeState `pappend`+                        ManyState manyBoolMaybeState+                -- the "parameter" is combined+                r' = runManyState r :: StateT (Many '[Int, Bool]) Maybe String+            -- functionality of both state in an Alternative fashion+            -- manyIntMaybeState suceeded+            runStateT r' ( (5 :: Int) ./ True ./ nil) `shouldBe` Just ("5", (6 :: Int) ./ True ./ nil)+            runStateT r' ( (5 :: Int) ./ False ./ nil) `shouldBe` Just ("5", (6 :: Int) ./ False ./ nil)+            -- manyBoolMaybeState suceeded+            runStateT r' ( (0 :: Int) ./ True ./ nil) `shouldBe` Just ("True", (0 :: Int) ./ False ./ nil)+            -- Both failed+            runStateT r' ( (0 :: Int) ./ False ./ nil) `shouldBe` Nothing++        it "it can 'papply' to combine state runners 'Applicative'ly" $ do+            let r = (\a b -> a <> "." <> b) <$> ManyState manyIntMaybeState &<*>+                        ManyState manyBoolMaybeState+                -- the "parameter" is combined+                r' = runManyState r :: StateT (Many '[Int, Bool]) Maybe String+            -- functionality of both readers in an Applicative fashion+            runStateT r' ( (5 :: Int) ./ True ./ nil) `shouldBe` Just ("5.True", (6 :: Int) ./ False ./ nil)+            runStateT r' ( (5 :: Int) ./ False ./ nil) `shouldBe` Nothing+            runStateT r' ( (0 :: Int) ./ True ./ nil) `shouldBe` Nothing+            runStateT r' ( (0 :: Int) ./ False ./ nil) `shouldBe` Nothing+++        it "it can 'pbind' to combine state runners 'Monad'ically" $ do+            let r = ManyState manyIntMaybeState &>>= \a ->+                        case a of+                            "1" -> ManyState manyBoolMaybeState+                            _ -> empty+                -- the "parameter" is combined+                r' = runManyState r :: StateT (Many '[Int, Bool]) Maybe String+            -- functionality of both readers in an Monad fashion+            runStateT r' ( (1 :: Int) ./ True ./ nil) `shouldBe` Just ("True", (2 :: Int) ./ False ./ nil)+            runStateT r' ( (1 :: Int) ./ False ./ nil) `shouldBe` Nothing+            runStateT r' ( (5 :: Int) ./ True ./ nil) `shouldBe` Nothing+            runStateT r' ( (5 :: Int) ./ False ./ nil) `shouldBe` Nothing+            runStateT r' ( (0 :: Int) ./ True ./ nil) `shouldBe` Nothing+            runStateT r' ( (0 :: Int) ./ False ./ nil) `shouldBe` Nothing
+ test/Spec.hs view
@@ -0,0 +1,1 @@+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}