packages feed

polysemy-zoo 0.1.2.0 → 0.1.2.1

raw patch · 7 files changed

+237/−68 lines, 7 filesdep ~polysemyPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: polysemy

API changes (from Hackage documentation)

+ Polysemy.Several: [:::] :: a -> HList (b :: [Type]) -> HList (a : b)
+ Polysemy.Several: [HNil] :: HList '[]
+ Polysemy.Several: data HList a
+ Polysemy.Several: infixr 5 :::
+ Polysemy.Several: runSeveral :: (forall r k x. k -> Sem (e k : r) x -> Sem r x) -> HList t -> Sem (TypeConcat (TypeMap e t) r) a -> Sem r a
+ Polysemy.Several: type family TypeConcat (a :: [t]) (b :: [t])
- Polysemy.KVStore: lookupKV :: forall k_acRs v_acRt r_afMP. Member (KVStore k_acRs v_acRt) r_afMP => k_acRs -> Sem r_afMP (Maybe v_acRt)
+ Polysemy.KVStore: lookupKV :: forall k_acRv v_acRw r_afMS. Member (KVStore k_acRv v_acRw) r_afMS => k_acRv -> Sem r_afMS (Maybe v_acRw)
- Polysemy.KVStore: updateKV :: forall k_acRs v_acRt r_afMQ. Member (KVStore k_acRs v_acRt) r_afMQ => k_acRs -> Maybe v_acRt -> Sem r_afMQ ()
+ Polysemy.KVStore: updateKV :: forall k_acRv v_acRw r_afMT. Member (KVStore k_acRv v_acRw) r_afMT => k_acRv -> Maybe v_acRw -> Sem r_afMT ()
- Polysemy.Random: random :: forall r_aqze a_aqxt. (Member Random r_aqze, Random a_aqxt) => Sem r_aqze a_aqxt
+ Polysemy.Random: random :: forall r_aqzb a_aqxq. (Member Random r_aqzb, Random a_aqxq) => Sem r_aqzb a_aqxq
- Polysemy.Random: randomR :: forall r_aqzf a_aqxt. (Member Random r_aqzf, Random a_aqxt) => (a_aqxt, a_aqxt) -> Sem r_aqzf a_aqxt
+ Polysemy.Random: randomR :: forall r_aqzc a_aqxq. (Member Random r_aqzc, Random a_aqxq) => (a_aqxq, a_aqxq) -> Sem r_aqzc a_aqxq
- Polysemy.RandomFu: getRandomPrim :: forall r_atnn r_ati9. Member RandomFu r_atnn => Prim r_ati9 -> Sem r_atnn r_ati9
+ Polysemy.RandomFu: getRandomPrim :: forall r_atnk r_ati6. Member RandomFu r_atnk => Prim r_ati6 -> Sem r_atnk r_ati6
- Polysemy.RandomFu: sampleRVar :: forall r_atnm r_ati9. Member RandomFu r_atnm => RVar r_ati9 -> Sem r_atnm r_ati9
+ Polysemy.RandomFu: sampleRVar :: forall r_atnj r_ati6. Member RandomFu r_atnj => RVar r_ati6 -> Sem r_atnj r_ati6

Files

ChangeLog.md view
@@ -1,5 +1,10 @@ # Changelog for polysemy-zoo +## 0.1.2.1 (2019-06-12)++- Update the tests to run against `polysemy-0.4.0.0`++ ## 0.1.2.0 (2019-06-01)  - Added `Polysemy.MTL` for inter-op with MTL (thanks to @adamConnerSax)
polysemy-zoo.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: 07f2fe507c2afe8ef70bcc42b26d3eaa3541eee97656ce45a5afa9ea207334cc+-- hash: b8422eaa237bad8199d235d37dd432322f191094275f7e61d94fb38fb030d101  name:           polysemy-zoo-version:        0.1.2.0+version:        0.1.2.1 synopsis:       Experimental, user-contributed effects and interpreters for polysemy description:    Please see the README on GitHub at <https://github.com/isovector/polysemy-zoo#readme> category:       Polysemy@@ -35,6 +35,7 @@       Polysemy.Operators       Polysemy.Random       Polysemy.RandomFu+      Polysemy.Several   other-modules:       Paths_polysemy_zoo   hs-source-dirs:@@ -62,6 +63,7 @@       KVStoreSpec       MTLSpec       RandomFuSpec+      SeveralSpec       Paths_polysemy_zoo   hs-source-dirs:       test@@ -73,7 +75,7 @@     , containers     , hspec     , mtl >=2.0.1.0 && <3.0.0.0-    , polysemy >=0.3+    , polysemy >=0.4     , polysemy-plugin     , polysemy-zoo     , random >=1.1 && <1.2
src/Polysemy/Operators.hs view
@@ -1,62 +1,75 @@-{-|--Operators meant as replacements for traditional 'Sem' type and 'Member' /-'Members' constraints, that allow you to specify types of your actions and-interpreters in more concise way, e.g. without mentioning unnecessary-details:--@-foo :: 'Member' ('Lift' 'IO') r => 'String' -> 'Int' -> 'Sem' r ()-@--can be written simply as:--@-foo :: 'String' -> 'Int' -> 'IO' '~@>' ()-@--Working example with operators:--@-import Data.Function-import Polysemy-import Polysemy.Operators-import Polysemy.Random--data ConsoleIO m a where-  WriteStrLn ::           'String' -> ConsoleIO m ()-  ReadStrLn  ::                     ConsoleIO m 'String'-  ShowStrLn  :: 'Show' a => a      -> ConsoleIO m ()--'makeSem' ''ConsoleIO---- runConsoleIO :: Member (Lift IO) r => Sem (ConsoleIO:r) a -> Sem r a-runConsoleIO :: ConsoleIO:r '@>' a -> 'IO' '~@' r '@>' a-runConsoleIO = 'interpret' \\case-  WriteStrLn s -> 'sendM' '$' 'putStrLn' s-  ReadStrLn    -> 'sendM'   'getLine'-  ShowStrLn  v -> 'sendM' '$' 'print' v--main :: 'IO' ()-main = program-     'Data.Function.&' runConsoleIO-     'Data.Function.&' 'Polysemy.Random.runRandomIO'-     'Data.Function.&' 'runM'---- program :: Members \'[Random, ConsoleIO] r => Sem r ()-program :: \'['Polysemy.Random', ConsoleIO] '>@>' ()-program = do-  writeStrLn "It works! Write something:"-  val <- readStrLn-  writeStrLn '$' "Here it is!: " '++' val-  num <- 'Polysemy.Random.random' \@'Int'-  writeStrLn '$' "Some random number:"-  showStrLn num-@--See documentation of specific operators for more details.---}+-- | Operators meant as replacements for traditional 'Sem' type and 'Member' /+-- 'Members' constraints, that allow you to specify types of your actions and+-- interpreters in more concise way, without mentioning unnecessary details:+--+-- @+-- foo :: 'Member' ('Lift' 'IO') r => 'String' -> 'Int' -> 'Sem' r ()+-- @+--+-- can be written simply as:+--+-- @+-- foo :: 'String' -> 'Int' -> 'IO' '~@>' ()+-- @+--+-- Working example with operators:+--+-- @+-- import Data.Function+-- import Polysemy+-- import Polysemy.Operators+-- import Polysemy.Random+--+-- data ConsoleIO m a where+--   WriteStrLn ::           'String' -> ConsoleIO m ()+--   ReadStrLn  ::                     ConsoleIO m 'String'+--   ShowStrLn  :: 'Show' a => a      -> ConsoleIO m ()+--+-- 'makeSem' ''ConsoleIO+--+-- -- runConsoleIO :: Member (Lift IO) r => Sem (ConsoleIO : r) a -> Sem r a+-- runConsoleIO :: ConsoleIO : r '@>' a -> 'IO' '~@' r '@>' a+-- runConsoleIO = 'interpret' \\case+--   WriteStrLn s -> 'sendM' '$' 'putStrLn' s+--   ReadStrLn    -> 'sendM'   'getLine'+--   ShowStrLn  v -> 'sendM' '$' 'print' v+--+-- main :: 'IO' ()+-- main = program+--      'Data.Function.&' runConsoleIO+--      'Data.Function.&' 'Polysemy.Random.runRandomIO'+--      'Data.Function.&' 'runM'+--+-- -- program :: Members \'[Random, ConsoleIO] r => Sem r ()+-- program :: \'['Polysemy.Random', ConsoleIO] '>@>' ()+-- program = do+--   writeStrLn "It works! Write something:"+--   val <- readStrLn+--   writeStrLn '$' "Here it is!: " '++' val+--   num <- 'Polysemy.Random.random' \@'Int'+--   writeStrLn '$' "Some random number:"+--   showStrLn num+-- @+--+-- Please keep in mind that constraints created through these operators are+-- limited to the action they are being used on, for example:+--+-- @+-- foo :: (forall x. r '@>' x -> 'IO' x)+--     -> 'IO' (forall a. Foo : r '@>' a -> 'IO' '~@' r '@>' a)+-- @+--+-- The first argument in the signature above won't have access to the+-- @('IO' ~\@)@ constraint in the result - in such cases, use a normal+-- constraint instead:+--+-- @+-- foo :: 'Member' ('Lift' 'IO') r+--     => (forall x. r '@>' x -> 'IO' x)+--     -> 'IO' (forall a. Foo : r '@>' a -> r '@>' a)+-- @+--+-- See the documentation of specific operators for more details.  module Polysemy.Operators   ( -- * 'Sem' operators@@ -80,16 +93,13 @@  import Polysemy ------------------------------------------------------------------------------- -- Miscellaneous -------------------------------------------------------------------------------------------------------------------------------------------- -- | Gets list of effects from 'Sem'. type family SemList s where   SemList (Sem r _) = r ------------------------------------------------------------------------------- -- Operators ------------------------------------------------------------------------------------------------------------------------------------------------+ -- $SemOperators -- Infix equivalents of 'Sem' with versions for specifiying list of effects -- ('@>'), single effect ('@-') and single monad ('@~') as effects of union.
+ src/Polysemy/Several.hs view
@@ -0,0 +1,73 @@+{-# LANGUAGE BlockArguments  #-}+{-# LANGUAGE TemplateHaskell #-}++module Polysemy.Several+        ( -- * Data+          HList(..)+        , TypeMap+        , TypeConcat+        , runSeveral+        )+where++import Polysemy+import Data.Kind++------------------------------------------------------------------------------+-- | A list capable of storing values of different types. Like the Sem type,+-- it uses a type level list to keep track of what's stored inside. Creating an+-- HList looks like:+--+-- > 1 ::: "test" ::: True ::: HNil+infixr 5 :::+data HList a where+    HNil  :: HList '[]+    (:::) :: a -> HList (b :: [Type]) -> HList (a ': b)++type Eff = (Type -> Type) -> Type -> Type+------------------------------------------------------------------------------+-- | A map function over type level lists. For example, the following two+-- lines are equivalent:+--+-- > TypeMap Reader [Int, String, False]+-- > [Reader Int, Reader String, Reader Bool]+type family TypeMap (f :: a -> b) (xs :: [a]) where+    TypeMap _ '[]       = '[]+    TypeMap f (x ': xs) = f x ': TypeMap f xs++------------------------------------------------------------------------------+-- | Like ++ but at the type level. The following two lines are equivalent:+--+-- > TypeConcat [Int, String] [Bool]+-- > [Int, String, Bool]+type family TypeConcat (a :: [t]) (b :: [t]) where+    TypeConcat '[] b = b+    TypeConcat (a ': as) b = a ': TypeConcat as b++------------------------------------------------------------------------------+-- | A helper function for building new runners which accept HLists intsead of+-- individual elements. If you would normally write+--+-- > f 5 . f "Text" . f True+--+-- then this function can turn that into+--+-- > runSeveral f (True ::: "Text" ::: 5 ::: HNil)+--+-- For example, a runReaders function could be implemented as:+--+-- > runReaders :: HList t -> Sem (TypeConcat (TypeMap Reader t) r) a -> Sem r a+-- > runReaders = runSeveral runReader+--+-- Likewise, runStates could be the following if you didn't want the returned+-- state:+--+-- > runStates :: HList t -> Sem (TypeConcat (TypeMap State t) r) a -> Sem r a+-- > runStates = runSeveral (fmap (fmap snd) . runState)+runSeveral+    :: (forall r k x. k -> Sem (e k ': r) x -> Sem r x)+    -> HList t+    -> Sem (TypeConcat (TypeMap e t) r) a+    -> Sem r a+runSeveral f (a ::: as) = runSeveral f as . f a+runSeveral _ HNil       = id
test/IdempotentLoweringSpec.hs view
@@ -32,7 +32,7 @@ spec :: Spec spec = describe "Idempotent Lowering" $ do   it "should persist an IORef through a bracket" $ do-    runIt <- nat runM .@! const (runStateInIO 0) .@! liftNat runResource+    runIt <- nat runM .@! const (runStateInIO 0) .@! liftNat runResourceInIO     result <- runIt test     result `shouldBe` (3 :: Int) 
test/MTLSpec.hs view
@@ -1,6 +1,7 @@ {-# LANGUAGE OverloadedStrings   #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications    #-}+ module MTLSpec where  import           Polysemy@@ -70,7 +71,7 @@       ++ " In this case, 16, the sum of \"init [1,5,5,5,5]\""       )     $ do-        flip shouldBe 16 . sum . fst . run . runWriter $ do+        flip shouldBe 16 . sum @[] . fst . run . runWriter $ do           tell [1]           absorbWriter $ replicateTell 2 5           censor init $ absorbWriter $ replicateTell 2 5
+ test/SeveralSpec.hs view
@@ -0,0 +1,78 @@+module SeveralSpec where++import           Polysemy+import           Polysemy.State+import           Polysemy.Reader+import           Polysemy.Input+import           Polysemy.Several+import           Test.Hspec+++readerProgram :: ( Member (Reader String) r+                 , Member (Reader Int) r+                 , Member (Reader Bool) r+                 , Members [Reader String, Reader Int, Reader Bool] r+                     ~ Members (TypeMap Reader [String, Int, Bool]) r+                 ) => Sem r (Int, String, Bool)+readerProgram = do+  a <- ask @Int+  b <- ask @String+  c <- ask @Bool+  pure $ (a, b, c)++stateProgram :: ( Member (State String) r+                , Member (State Int) r+                , Member (State Bool) r+                , Members [State String, State Int, State Bool] r+                    ~ Members (TypeMap State [String, Int, Bool]) r+                ) => Sem r (Int, String, Bool)+stateProgram = do+  put @Int 5+  put "Changed"+  a <- get @Int+  b <- get @String+  c <- get @Bool+  pure $ (a, b, c)++inputProgram :: ( Member (Input String) r+                , Member (Input Int) r+                , Member (Input Bool) r+                , Members [Input String, Input Int, Input Bool] r+                    ~ Members (TypeMap Input [String, Int, Bool]) r+                ) => Sem r (Int, String, Bool)+inputProgram = do+  a <- input @Int+  b <- input @String+  c <- input @Bool+  pure $ (a, b, c)+++runReaders = runSeveral runReader++runStates = runSeveral (fmap (fmap snd) . runState)++runConstInputs = runSeveral runConstInput++spec = do+  describe "runReaders" $ do+    let original = runReader 5 . runReader "test" . runReader True $ readerProgram+        new = runReaders (True ::: "test" ::: 5 ::: HNil) readerProgram++    it "should be equivalent to composed runReader" $ do+      run original `shouldBe` run new++  describe "runStates" $ do+    let getResult = fmap $ snd . snd . snd+        original = getResult $ runState 5 . runState "test" . runState True $ stateProgram+        new = runStates (True ::: "test" ::: 5 ::: HNil) stateProgram++    it "should be equivalent to composed runState" $ do+      run original `shouldBe` run new++  describe "runConstInput" $ do+    let original = runConstInput 5 . runConstInput "test"+                                   . runConstInput True $ inputProgram+        new = runConstInputs (True ::: "test" ::: 5 ::: HNil) inputProgram++    it "should be equivalent to composed runConstInput" $ do+      run original `shouldBe` run new