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 +5/−0
- parameterized.cabal +16/−2
- src/Parameterized/Control/Applicative.hs +2/−4
- src/Parameterized/Control/Monad.hs +0/−1
- src/Parameterized/Control/Monad/Trans/Reader.hs +4/−0
- src/Parameterized/Control/Monad/Trans/State/Strict.hs +1/−0
- src/Parameterized/Data/Monoid.hs +4/−6
- src/Parameterized/TypeLevel.hs +10/−10
- test/Parameterized/Control/Monad/Trans/Reader/ReaderSpec.hs +247/−0
- test/Parameterized/Control/Monad/Trans/State/Strict/StateSpec.hs +95/−0
- test/Spec.hs +1/−0
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 #-}