polysemy 0.1.2.0 → 0.1.2.1
raw patch · 17 files changed
+323/−192 lines, 17 filesdep ~criteriondep ~dump-coredep ~freePVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependency ranges changed: criterion, dump-core, free, freer-simple, hspec, mtl
API changes (from Hackage documentation)
- Polysemy.Internal.Union: instance GHC.Base.Functor m => GHC.Base.Functor (Polysemy.Internal.Union.Union r m)
+ Polysemy.Internal: instance Polysemy.Internal.PluginLookup.PluginLookup Polysemy.Internal.PluginLookup.Plugin
+ Polysemy.Internal.Effect: fmap' :: (Effect e, Functor (e m)) => (a -> b) -> e m a -> e m b
+ Polysemy.Internal.Union: instance Data.Type.Equality.TestEquality Polysemy.Internal.Union.SNat
+ Polysemy.Internal.Union: instance GHC.Base.Functor (Polysemy.Internal.Union.Union r m)
+ Polysemy.State: hoistStateIntoStateT :: Sem (State s : r) a -> StateT s (Sem r) a
- Polysemy: intercept :: (Member e r, FirstOrder e "intercept") => (forall x m. e m x -> Sem r x) -> Sem r a -> Sem r a
+ Polysemy: intercept :: (Member e r, FirstOrder m0 e "intercept") => (forall x m. e m x -> Sem r x) -> Sem r a -> Sem r a
- Polysemy: interpret :: FirstOrder e "interpret" => (forall x m. e m x -> Sem r x) -> Sem (e : r) a -> Sem r a
+ Polysemy: interpret :: FirstOrder m0 e "interpret" => (forall x m. e m x -> Sem r x) -> Sem (e : r) a -> Sem r a
- Polysemy: reinterpret :: FirstOrder e1 "reinterpret" => (forall m x. e1 m x -> Sem (e2 : r) x) -> Sem (e1 : r) a -> Sem (e2 : r) a
+ Polysemy: reinterpret :: FirstOrder m0 e1 "reinterpret" => (forall m x. e1 m x -> Sem (e2 : r) x) -> Sem (e1 : r) a -> Sem (e2 : r) a
- Polysemy: reinterpret2 :: FirstOrder e1 "reinterpret2" => (forall m x. e1 m x -> Sem (e2 : (e3 : r)) x) -> Sem (e1 : r) a -> Sem (e2 : (e3 : r)) a
+ Polysemy: reinterpret2 :: FirstOrder m0 e1 "reinterpret2" => (forall m x. e1 m x -> Sem (e2 : (e3 : r)) x) -> Sem (e1 : r) a -> Sem (e2 : (e3 : r)) a
- Polysemy: reinterpret3 :: FirstOrder e1 "reinterpret3" => (forall m x. e1 m x -> Sem (e2 : (e3 : (e4 : r))) x) -> Sem (e1 : r) a -> Sem (e2 : (e3 : (e4 : r))) a
+ Polysemy: reinterpret3 :: FirstOrder m0 e1 "reinterpret3" => (forall m x. e1 m x -> Sem (e2 : (e3 : (e4 : r))) x) -> Sem (e1 : r) a -> Sem (e2 : (e3 : (e4 : r))) a
- Polysemy.Error: catch :: forall e_alDv a_alDx. forall r_alPl. Member (Error e_alDv) r_alPl => Sem r_alPl a_alDx -> (e_alDv -> Sem r_alPl a_alDx) -> Sem r_alPl a_alDx
+ Polysemy.Error: catch :: forall e_al12 a_al14. forall r_alcS. Member (Error e_al12) r_alcS => Sem r_alcS a_al14 -> (e_al12 -> Sem r_alcS a_al14) -> Sem r_alcS a_al14
- Polysemy.Error: throw :: forall e_alDs a_alDu. forall r_alPk. Member (Error e_alDs) r_alPk => e_alDs -> Sem r_alPk a_alDu
+ Polysemy.Error: throw :: forall e_al0Z a_al11. forall r_alcR. Member (Error e_al0Z) r_alcR => e_al0Z -> Sem r_alcR a_al11
- Polysemy.Input: input :: forall i_aqR2. forall r_aqRN. Member (Input i_aqR2) r_aqRN => Sem r_aqRN i_aqR2
+ Polysemy.Input: input :: forall i_aqBI. forall r_aqCt. Member (Input i_aqBI) r_aqCt => Sem r_aqCt i_aqBI
- Polysemy.Internal.Combinators: intercept :: (Member e r, FirstOrder e "intercept") => (forall x m. e m x -> Sem r x) -> Sem r a -> Sem r a
+ Polysemy.Internal.Combinators: intercept :: (Member e r, FirstOrder m0 e "intercept") => (forall x m. e m x -> Sem r x) -> Sem r a -> Sem r a
- Polysemy.Internal.Combinators: interpret :: FirstOrder e "interpret" => (forall x m. e m x -> Sem r x) -> Sem (e : r) a -> Sem r a
+ Polysemy.Internal.Combinators: interpret :: FirstOrder m0 e "interpret" => (forall x m. e m x -> Sem r x) -> Sem (e : r) a -> Sem r a
- Polysemy.Internal.Combinators: reinterpret :: FirstOrder e1 "reinterpret" => (forall m x. e1 m x -> Sem (e2 : r) x) -> Sem (e1 : r) a -> Sem (e2 : r) a
+ Polysemy.Internal.Combinators: reinterpret :: FirstOrder m0 e1 "reinterpret" => (forall m x. e1 m x -> Sem (e2 : r) x) -> Sem (e1 : r) a -> Sem (e2 : r) a
- Polysemy.Internal.Combinators: reinterpret2 :: FirstOrder e1 "reinterpret2" => (forall m x. e1 m x -> Sem (e2 : (e3 : r)) x) -> Sem (e1 : r) a -> Sem (e2 : (e3 : r)) a
+ Polysemy.Internal.Combinators: reinterpret2 :: FirstOrder m0 e1 "reinterpret2" => (forall m x. e1 m x -> Sem (e2 : (e3 : r)) x) -> Sem (e1 : r) a -> Sem (e2 : (e3 : r)) a
- Polysemy.Internal.Combinators: reinterpret3 :: FirstOrder e1 "reinterpret3" => (forall m x. e1 m x -> Sem (e2 : (e3 : (e4 : r))) x) -> Sem (e1 : r) a -> Sem (e2 : (e3 : (e4 : r))) a
+ Polysemy.Internal.Combinators: reinterpret3 :: FirstOrder m0 e1 "reinterpret3" => (forall m x. e1 m x -> Sem (e2 : (e3 : (e4 : r))) x) -> Sem (e1 : r) a -> Sem (e2 : (e3 : (e4 : r))) a
- Polysemy.Internal.CustomErrors: type FirstOrder e fn = forall m. Coercible (e m) (e (FirstOrderError e fn))
+ Polysemy.Internal.CustomErrors: type FirstOrder m e fn = Coercible (e m) (e (FirstOrderError e fn))
- Polysemy.Internal.Effect: class (forall m. Functor m => Functor (e m)) => Effect e
+ Polysemy.Internal.Effect: class Effect e
- Polysemy.Internal.Union: [SS] :: Typeable n => SNat n -> SNat ( 'S n)
+ Polysemy.Internal.Union: [SS] :: SNat n -> SNat ( 'S n)
- Polysemy.Output: output :: forall o_aqf0. forall r_aqfK. Member (Output o_aqf0) r_aqfK => o_aqf0 -> Sem r_aqfK ()
+ Polysemy.Output: output :: forall o_apZS. forall r_aq0C. Member (Output o_apZS) r_aq0C => o_apZS -> Sem r_aq0C ()
- Polysemy.Random: random :: forall x_apCy. Random x_apCy => forall r_apE0. Member Random r_apE0 => Sem r_apE0 x_apCy
+ Polysemy.Random: random :: forall x_apnH. Random x_apnH => forall r_app9. Member Random r_app9 => Sem r_app9 x_apnH
- Polysemy.Random: randomR :: forall x_apCA. Random x_apCA => forall r_apE1. Member Random r_apE1 => (x_apCA, x_apCA) -> Sem r_apE1 x_apCA
+ Polysemy.Random: randomR :: forall x_apnJ. Random x_apnJ => forall r_appa. Member Random r_appa => (x_apnJ, x_apnJ) -> Sem r_appa x_apnJ
- Polysemy.Reader: ask :: forall i_arbR. forall r_ard9. Member (Reader i_arbR) r_ard9 => Sem r_ard9 i_arbR
+ Polysemy.Reader: ask :: forall i_aqWk. forall r_aqXC. Member (Reader i_aqWk) r_aqXC => Sem r_aqXC i_aqWk
- Polysemy.Reader: local :: forall i_arbT a_arbV. forall r_arda. Member (Reader i_arbT) r_arda => (i_arbT -> i_arbT) -> Sem r_arda a_arbV -> Sem r_arda a_arbV
+ Polysemy.Reader: local :: forall i_aqWm a_aqWo. forall r_aqXD. Member (Reader i_aqWm) r_aqXD => (i_aqWm -> i_aqWm) -> Sem r_aqXD a_aqWo -> Sem r_aqXD a_aqWo
- Polysemy.Resource: bracket :: forall a_XnRj b_anRj. forall r_anSj. Member Resource r_anSj => Sem r_anSj a_XnRj -> (a_XnRj -> Sem r_anSj ()) -> (a_XnRj -> Sem r_anSj b_anRj) -> Sem r_anSj b_anRj
+ Polysemy.Resource: bracket :: forall a_XnjS b_anjS. forall r_ankS. Member Resource r_ankS => Sem r_ankS a_XnjS -> (a_XnjS -> Sem r_ankS ()) -> (a_XnjS -> Sem r_ankS b_anjS) -> Sem r_ankS b_anjS
- Polysemy.State: get :: forall s_aocD. forall r_aodO. Member (State s_aocD) r_aodO => Sem r_aodO s_aocD
+ Polysemy.State: get :: forall s_anF8. forall r_anGj. Member (State s_anF8) r_anGj => Sem r_anGj s_anF8
- Polysemy.State: put :: forall s_aocF. forall r_aodP. Member (State s_aocF) r_aodP => s_aocF -> Sem r_aodP ()
+ Polysemy.State: put :: forall s_anFa. forall r_anGk. Member (State s_anFa) r_anGk => s_anFa -> Sem r_anGk ()
- Polysemy.Trace: trace :: forall r_aryb. Member Trace r_aryb => String -> Sem r_aryb ()
+ Polysemy.Trace: trace :: forall r_arim. Member Trace r_arim => String -> Sem r_arim ()
- Polysemy.Writer: censor :: forall o_arYf a_arYh. forall r_as06. Member (Writer o_arYf) r_as06 => (o_arYf -> o_arYf) -> Sem r_as06 a_arYh -> Sem r_as06 a_arYh
+ Polysemy.Writer: censor :: forall o_arI2 a_arI4. forall r_arJT. Member (Writer o_arI2) r_arJT => (o_arI2 -> o_arI2) -> Sem r_arJT a_arI4 -> Sem r_arJT a_arI4
- Polysemy.Writer: listen :: forall o_arYc a_XrYf. forall r_as05. Member (Writer o_arYc) r_as05 => Sem r_as05 a_XrYf -> Sem r_as05 (o_arYc, a_XrYf)
+ Polysemy.Writer: listen :: forall o_arHZ a_XrI2. forall r_arJS. Member (Writer o_arHZ) r_arJS => Sem r_arJS a_XrI2 -> Sem r_arJS (o_arHZ, a_XrI2)
- Polysemy.Writer: tell :: forall o_arYa. forall r_as04. Member (Writer o_arYa) r_as04 => o_arYa -> Sem r_as04 ()
+ Polysemy.Writer: tell :: forall o_arHX. forall r_arJR. Member (Writer o_arHX) r_arJR => o_arHX -> Sem r_arJR ()
Files
- ChangeLog.md +7/−0
- README.md +82/−28
- polysemy.cabal +113/−116
- src/Polysemy/Internal.hs +12/−1
- src/Polysemy/Internal/Combinators.hs +7/−6
- src/Polysemy/Internal/CustomErrors.hs +6/−2
- src/Polysemy/Internal/Effect.hs +16/−4
- src/Polysemy/Internal/Fixpoint.hs +2/−0
- src/Polysemy/Internal/Lift.hs +2/−0
- src/Polysemy/Internal/NonDet.hs +2/−0
- src/Polysemy/Internal/PluginLookup.hs +9/−0
- src/Polysemy/Internal/TH/Effect.hs +2/−0
- src/Polysemy/Internal/TH/Performance.hs +2/−0
- src/Polysemy/Internal/Tactics.hs +2/−1
- src/Polysemy/Internal/Union.hs +21/−30
- src/Polysemy/State.hs +37/−3
- test/FusionSpec.hs +1/−1
ChangeLog.md view
@@ -1,5 +1,12 @@ # Changelog for polysemy +## 0.1.2.1 (2019-05-18)++- Give explicit package bounds for dependencies+- Haddock improvements+- Remove `Typeable` machinery from `Polysemy.Internal.Union` (thanks to+ @googleson78)+ ## 0.1.2.0 (2019-04-26) - `runInputAsReader`, `runTraceAsOutput` and `runOutputAsWriter` have more
README.md view
@@ -26,7 +26,26 @@ It's like `fused-effects` but with an order of magnitude less boilerplate. +Additionally, unlike `mtl`, `polysemy` has no functional dependencies, so you+can use multiple copies of the same effect. This alleviates the need for ~~ugly+hacks~~band-aids like [classy+lenses](http://hackage.haskell.org/package/lens-4.17.1/docs/Control-Lens-TH.html#v:makeClassy),+the [`ReaderT`+pattern](https://www.fpcomplete.com/blog/2017/06/readert-design-pattern) and+nicely solves the [trouble with typed+errors](https://www.parsonsmatt.org/2018/11/03/trouble_with_typed_errors.html). +Concerned about type inference? Check out+[polysemy-plugin](https://github.com/isovector/polysemy/tree/master/polysemy-plugin),+which should perform just as well as `mtl`'s! Add `polysemy-plugin` to your package.yaml+or .cabal file's dependencies section to use. Then turn it on with a pragma in your source-files:++```haskell+{-# OPTIONS_GHC -fplugin=Polysemy.Plugin #-}+```+Or by adding `-fplugin=Polysemy.Plugin` to your package.yaml/.cabal file `ghc-options` section.++ ## Features * *Effects are higher-order,* meaning it's trivial to write `bracket` and `local`@@ -48,23 +67,59 @@ Extensions](https://github.com/isovector/polysemy#necessary-language-extensions) before trying these yourself! -Console effect:+Teletype effect: ```haskell {-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE LambdaCase, BlockArguments #-}+{-# LANGUAGE GADTs, FlexibleContexts, TypeOperators, DataKinds, PolyKinds #-} import Polysemy+import Polysemy.Input+import Polysemy.Output -data Console m a where- ReadTTY :: Console m String- WriteTTY :: String -> Console m ()+data Teletype m a where+ ReadTTY :: Teletype m String+ WriteTTY :: String -> Teletype m () -makeSem ''Console+makeSem ''Teletype -runConsoleIO :: Member (Lift IO) r => Sem (Console ': r) a -> Sem r a-runConsoleIO = interpret $ \case+runTeletypeIO :: Member (Lift IO) r => Sem (Teletype ': r) a -> Sem r a+runTeletypeIO = interpret $ \case ReadTTY -> sendM getLine WriteTTY msg -> sendM $ putStrLn msg++runTeletypePure :: [String] -> Sem (Teletype ': r) a -> Sem r ([String], a)+runTeletypePure i+ = runFoldMapOutput pure -- For each WriteTTY in our program, consume an output by appending it to the list in a ([String], a)+ . runListInput i -- Treat each element of our list of strings as a line of input+ . reinterpret2 \case -- Reinterpret our effect in terms of Input and Output+ ReadTTY -> maybe "" id <$> input+ WriteTTY msg -> output msg+++echo :: Member Teletype r => Sem r ()+echo = do+ i <- readTTY+ case i of+ "" -> pure ()+ _ -> writeTTY i >> echo+++-- Let's pretend+echoPure :: [String] -> Sem '[] ([String], ())+echoPure = flip runTeletypePure echo++pureOutput :: [String] -> [String]+pureOutput = fst . run . echoPure++-- Now let's do things+echoIO :: Sem '[Lift IO] ()+echoIO = runTeletypeIO echo++-- echo forever+main :: IO ()+main = runM echoIO ``` @@ -72,31 +127,31 @@ ```haskell {-# LANGUAGE TemplateHaskell #-}--import qualified Control.Exception as X-import Polysemy+{-# LANGUAGE LambdaCase, BlockArguments #-}+{-# LANGUAGE GADTs, FlexibleContexts, TypeOperators, DataKinds, PolyKinds, TypeApplications #-} -data Resource m a where- Bracket :: m a -> (a -> m ()) -> (a -> m b) -> Resource m b+import Prelude hiding (throw, catch, bracket)+import Polysemy+import Polysemy.Input+import Polysemy.Output+import Polysemy.Error+import Polysemy.Resource -makeSem ''Resource+-- Using Teletype effect from above -runResource- :: forall r a- . Member (Lift IO) r- => (∀ x. Sem r x -> IO x)- -> Sem (Resource ': r) a- -> Sem r a-runResource finish = interpretH $ \case- Bracket alloc dealloc use -> do- a <- runT alloc- d <- bindT dealloc- u <- bindT use+data CustomException = ThisException | ThatException deriving Show - let runIt :: Sem (Resource ': r) x -> IO x- runIt = finish .@ runResource+program :: Members '[Resource, Teletype, Error CustomException] r => Sem r ()+program = catch @CustomException work $ \e -> writeTTY ("Caught " ++ show e)+ where work = bracket (readTTY) (const $ writeTTY "exiting bracket") $ \input -> do+ writeTTY "entering bracket"+ case input of+ "explode" -> throw ThisException+ "weird stuff" -> writeTTY input >> throw ThatException+ _ -> writeTTY input >> writeTTY "no exceptions" - sendM $ X.bracket (runIt a) (runIt . d) (runIt . u)+main :: IO (Either CustomException ())+main = (runM .@ runResource .@@ runErrorInIO @CustomException) . runTeletypeIO $ program ``` Easy.@@ -159,4 +214,3 @@ - TypeOperators - TypeFamilies ```-
polysemy.cabal view
@@ -1,133 +1,130 @@ cabal-version: 1.12-name: polysemy-version: 0.1.2.0-license: BSD3-license-file: LICENSE-copyright: 2019 Sandy Maguire-maintainer: sandy@sandymaguire.me-author: Sandy Maguire-homepage: https://github.com/isovector/polysemy#readme-bug-reports: https://github.com/isovector/polysemy/issues-synopsis: Higher-order, low-boilerplate, zero-cost free monads.-description:- Please see the README on GitHub at <https://github.com/isovector/polysemy#readme>-category: Language-build-type: Simple++-- This file has been generated from package.yaml by hpack version 0.31.1.+--+-- see: https://github.com/sol/hpack+--+-- hash: 07720201673d182e7f285d795076b886bb48fb10b1704776922e431bf41b6c27++name: polysemy+version: 0.1.2.1+synopsis: Higher-order, low-boilerplate, zero-cost free monads.+description: Please see the README on GitHub at <https://github.com/isovector/polysemy#readme>+category: Language+homepage: https://github.com/isovector/polysemy#readme+bug-reports: https://github.com/isovector/polysemy/issues+author: Sandy Maguire+maintainer: sandy@sandymaguire.me+copyright: 2019 Sandy Maguire+license: BSD3+license-file: LICENSE+build-type: Simple extra-source-files: README.md ChangeLog.md source-repository head- type: git- location: https://github.com/isovector/polysemy+ type: git+ location: https://github.com/isovector/polysemy flag dump-core- description:- Dump HTML for the core generated by GHC during compilation- default: False- manual: True+ description: Dump HTML for the core generated by GHC during compilation+ manual: True+ default: False flag error-messages- description:- Provide custom error messages- manual: True+ description: Provide custom error messages+ manual: True+ default: True library- exposed-modules:- Polysemy- Polysemy.Error- Polysemy.Fixpoint- Polysemy.Input- Polysemy.Internal- Polysemy.Internal.Combinators- Polysemy.Internal.CustomErrors- Polysemy.Internal.Effect- Polysemy.Internal.Fixpoint- Polysemy.Internal.Lift- Polysemy.Internal.NonDet- Polysemy.Internal.Tactics- Polysemy.Internal.TH.Effect- Polysemy.Internal.TH.Performance- Polysemy.Internal.Union- Polysemy.IO- Polysemy.NonDet- Polysemy.Output- Polysemy.Random- Polysemy.Reader- Polysemy.Resource- Polysemy.State- Polysemy.Trace- Polysemy.Writer- hs-source-dirs: src- other-modules:- Paths_polysemy- default-language: Haskell2010- default-extensions: DataKinds DeriveFunctor FlexibleContexts GADTs- LambdaCase PolyKinds RankNTypes ScopedTypeVariables- StandaloneDeriving TypeApplications TypeOperators TypeFamilies- UnicodeSyntax- ghc-options: -O2 -Wall+ exposed-modules:+ Polysemy+ Polysemy.Error+ Polysemy.Fixpoint+ Polysemy.Input+ Polysemy.Internal+ Polysemy.Internal.Combinators+ Polysemy.Internal.CustomErrors+ Polysemy.Internal.Effect+ Polysemy.Internal.Fixpoint+ Polysemy.Internal.Lift+ Polysemy.Internal.NonDet+ Polysemy.Internal.Tactics+ Polysemy.Internal.TH.Effect+ Polysemy.Internal.TH.Performance+ Polysemy.Internal.Union+ Polysemy.IO+ Polysemy.NonDet+ Polysemy.Output+ Polysemy.Random+ Polysemy.Reader+ Polysemy.Resource+ Polysemy.State+ Polysemy.Trace+ Polysemy.Writer+ other-modules:+ Polysemy.Internal.PluginLookup+ hs-source-dirs:+ src+ default-extensions: DataKinds DeriveFunctor FlexibleContexts GADTs LambdaCase PolyKinds RankNTypes ScopedTypeVariables StandaloneDeriving TypeApplications TypeOperators TypeFamilies UnicodeSyntax+ ghc-options: -O2 -Wall+ build-depends:+ base >=4.7 && <5+ , mtl >=2.2.2 && <3+ , random >=1.1 && <1.2+ , syb >=0.7 && <0.8+ , template-haskell >=2.14.0.0 && <2.15+ , transformers >=0.5.5.0 && <0.6+ if flag(dump-core)+ ghc-options: -fplugin=DumpCore -fplugin-opt DumpCore:core-html build-depends:- base >=4.7 && <5,- mtl >=2.2.2 && <2.3,- random ==1.1.*,- syb ==0.7.*,- template-haskell >=2.14.0.0 && <2.15,- transformers >=0.5.5.0 && <0.6- - if flag(dump-core)- ghc-options: -fplugin=DumpCore -fplugin-opt DumpCore:core-html- build-depends:- dump-core >=0.1.3.2 && <0.2- - if flag(error-messages)- cpp-options: -DERROR_MESSAGES+ dump-core+ if flag(error-messages)+ cpp-options: -DERROR_MESSAGES+ default-language: Haskell2010 test-suite polysemy-test- type: exitcode-stdio-1.0- main-is: Main.hs- hs-source-dirs: test- other-modules:- FusionSpec- OutputSpec- Paths_polysemy- default-language: Haskell2010- default-extensions: DataKinds DeriveFunctor FlexibleContexts GADTs- LambdaCase PolyKinds RankNTypes ScopedTypeVariables- StandaloneDeriving TypeApplications TypeOperators TypeFamilies- UnicodeSyntax- ghc-options: -threaded -rtsopts -with-rtsopts=-N- build-depends:- base >=4.7 && <5,- hspec >=2.6.0 && <2.7,- inspection-testing >=0.4.1.1 && <0.5,- mtl >=2.2.2 && <2.3,- polysemy -any,- random ==1.1.*,- syb ==0.7.*,- template-haskell >=2.14.0.0 && <2.15,- transformers >=0.5.5.0 && <0.6+ type: exitcode-stdio-1.0+ main-is: Main.hs+ other-modules:+ FusionSpec+ OutputSpec+ Paths_polysemy+ hs-source-dirs:+ test+ default-extensions: DataKinds DeriveFunctor FlexibleContexts GADTs LambdaCase PolyKinds RankNTypes ScopedTypeVariables StandaloneDeriving TypeApplications TypeOperators TypeFamilies UnicodeSyntax+ ghc-options: -threaded -rtsopts -with-rtsopts=-N+ build-depends:+ base >=4.7 && <5+ , hspec >=2.6.0 && <3+ , inspection-testing >=0.4.1.1 && <0.5+ , mtl >=2.2.2 && <3+ , polysemy+ , random >=1.1 && <1.2+ , syb >=0.7 && <0.8+ , template-haskell >=2.14.0.0 && <2.15+ , transformers >=0.5.5.0 && <0.6+ default-language: Haskell2010 benchmark polysemy-bench- type: exitcode-stdio-1.0- main-is: countDown.hs- hs-source-dirs: bench- other-modules:- Poly- Paths_polysemy- default-language: Haskell2010- default-extensions: DataKinds DeriveFunctor FlexibleContexts GADTs- LambdaCase PolyKinds RankNTypes ScopedTypeVariables- StandaloneDeriving TypeApplications TypeOperators TypeFamilies- UnicodeSyntax- build-depends:- base >=4.7 && <5,- criterion >=1.5.3.0 && <1.6,- free ==5.1.*,- freer-simple >=1.2.1.0 && <1.3,- mtl >=2.2.2 && <2.3,- polysemy -any,- random ==1.1.*,- syb ==0.7.*,- template-haskell >=2.14.0.0 && <2.15,- transformers >=0.5.5.0 && <0.6+ type: exitcode-stdio-1.0+ main-is: countDown.hs+ other-modules:+ Poly+ Paths_polysemy+ hs-source-dirs:+ bench+ default-extensions: DataKinds DeriveFunctor FlexibleContexts GADTs LambdaCase PolyKinds RankNTypes ScopedTypeVariables StandaloneDeriving TypeApplications TypeOperators TypeFamilies UnicodeSyntax+ build-depends:+ base >=4.7 && <5+ , criterion+ , free+ , freer-simple+ , mtl+ , polysemy+ , random >=1.1 && <1.2+ , syb >=0.7 && <0.8+ , template-haskell >=2.14.0.0 && <2.15+ , transformers >=0.5.5.0 && <0.6+ default-language: Haskell2010
src/Polysemy/Internal.hs view
@@ -3,6 +3,9 @@ {-# LANGUAGE MonoLocalBinds #-} {-# LANGUAGE UndecidableInstances #-} +{-# OPTIONS_GHC -fno-warn-orphans #-}+{-# OPTIONS_HADDOCK not-home #-}+ module Polysemy.Internal ( Sem (..) , Member@@ -29,6 +32,7 @@ import Polysemy.Internal.Fixpoint import Polysemy.Internal.Lift import Polysemy.Internal.NonDet+import Polysemy.Internal.PluginLookup import Polysemy.Internal.Union @@ -73,7 +77,7 @@ -- As an example of keeping @r@ polymorphic, we can consider the type -- -- @--- 'Member' ('Polysemy.State' String) r => 'Sem' r ()+-- 'Member' ('Polysemy.State.State' String) r => 'Sem' r () -- @ -- -- to be a program with access to@@ -129,6 +133,13 @@ => (∀ x. Union r (Sem r) x -> m x) -> m a }+++------------------------------------------------------------------------------+-- | Due to a quirk of the GHC plugin interface, it's only easy to find+-- transitive dependencies if they define an orphan instance. This orphan+-- instance allows us to find "Polysemy.Internal" in the polysemy-plugin.+instance PluginLookup Plugin ------------------------------------------------------------------------------
src/Polysemy/Internal/Combinators.hs view
@@ -1,6 +1,7 @@ {-# LANGUAGE AllowAmbiguousTypes #-}-{-# LANGUAGE QuantifiedConstraints #-} +{-# OPTIONS_HADDOCK not-home #-}+ module Polysemy.Internal.Combinators ( -- * First order interpret@@ -39,7 +40,7 @@ -- | The simplest way to produce an effect handler. Interprets an effect @e@ by -- transforming it into other effects inside of @r@. interpret- :: FirstOrder e "interpret"+ :: FirstOrder m0 e "interpret" => (∀ x m. e m x -> Sem r x) -- ^ A natural transformation from the handled effect to other effects -- already in 'Sem'.@@ -153,7 +154,7 @@ -- 'Polysemy.State.runState', meaning it's free to 'reinterpret' in terms of -- the 'Polysemy.State.State' effect and immediately run it. reinterpret- :: FirstOrder e1 "reinterpret"+ :: FirstOrder m0 e1 "reinterpret" => (∀ m x. e1 m x -> Sem (e2 ': r) x) -- ^ A natural transformation from the handled effect to the new effect. -> Sem (e1 ': r) a@@ -184,7 +185,7 @@ ------------------------------------------------------------------------------ -- | Like 'reinterpret', but introduces /two/ intermediary effects. reinterpret2- :: FirstOrder e1 "reinterpret2"+ :: FirstOrder m0 e1 "reinterpret2" => (∀ m x. e1 m x -> Sem (e2 ': e3 ': r) x) -- ^ A natural transformation from the handled effect to the new effects. -> Sem (e1 ': r) a@@ -214,7 +215,7 @@ ------------------------------------------------------------------------------ -- | Like 'reinterpret', but introduces /three/ intermediary effects. reinterpret3- :: FirstOrder e1 "reinterpret3"+ :: FirstOrder m0 e1 "reinterpret3" => (∀ m x. e1 m x -> Sem (e2 ': e3 ': e4 ': r) x) -- ^ A natural transformation from the handled effect to the new effects. -> Sem (e1 ': r) a@@ -229,7 +230,7 @@ -- intercept other effects and insert logic around them. intercept :: ( Member e r- , FirstOrder e "intercept"+ , FirstOrder m0 e "intercept" ) => (∀ x m. e m x -> Sem r x) -- ^ A natural transformation from the handled effect to other effects
src/Polysemy/Internal/CustomErrors.hs view
@@ -1,9 +1,10 @@ {-# LANGUAGE AllowAmbiguousTypes #-} {-# LANGUAGE ConstraintKinds #-}-{-# LANGUAGE QuantifiedConstraints #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-} +{-# OPTIONS_HADDOCK not-home #-}+ module Polysemy.Internal.CustomErrors ( AmbiguousSend , Break@@ -118,7 +119,10 @@ ------------------------------------------------------------------------------ -- | This constraint gives helpful error messages if you attempt to use a -- first-order combinator with a higher-order type.-type FirstOrder e fn = ∀ m. Coercible (e m) (e (FirstOrderError e fn))+--+-- Note that the parameter 'm' is only required to work around supporting+-- versions of GHC without QuantifiedConstraints+type FirstOrder m e fn = Coercible (e m) (e (FirstOrderError e fn)) ------------------------------------------------------------------------------
src/Polysemy/Internal/Effect.hs view
@@ -1,6 +1,7 @@ {-# LANGUAGE DefaultSignatures #-}-{-# LANGUAGE QuantifiedConstraints #-} +{-# OPTIONS_HADDOCK not-home #-}+ module Polysemy.Internal.Effect where import Data.Coerce@@ -33,7 +34,18 @@ -- @ -- deriving instance Effect MyEffect -- @-class (∀ m. Functor m => Functor (e m)) => Effect e where+class Effect e where+ -- | Provide a specialised version of 'fmap' to work around versions of GHC+ -- that cannot express the quantified constraint '(∀ m. Functor m => Functor (e m))'+ --+ -- This must always be equal to 'fmap', and can be removed once GHC 8.6 is the+ -- minimum version supported by this library+ fmap' :: (a -> b) -> (e m a -> e m b)++ default fmap' :: Functor (e m) => (a -> b) -> (e m a -> e m b)+ fmap' = fmap+ {-# INLINE fmap' #-}+ -- | Higher-order effects require the ability to distribute state from other -- effects throughout themselves. This state is given by an initial piece of -- state @s ()@, and a distributive law that describes how to move the state@@ -65,7 +77,7 @@ -> (∀ x. s (m x) -> n (s x)) -> e m a -> e n (s a)- weave s _ = coerce . fmap (<$ s)+ weave s _ = coerce . fmap' (<$ s) {-# INLINE weave #-} -- | Lift a natural transformation from @m@ to @n@ over the effect. 'hoist'@@ -103,7 +115,7 @@ -> e m a -> e n a defaultHoist f- = fmap runIdentity+ = fmap' runIdentity . weave (Identity ()) (fmap Identity . f . runIdentity) {-# INLINE defaultHoist #-}
src/Polysemy/Internal/Fixpoint.hs view
@@ -1,3 +1,5 @@+{-# OPTIONS_HADDOCK not-home #-}+ module Polysemy.Internal.Fixpoint where ------------------------------------------------------------------------------
src/Polysemy/Internal/Lift.hs view
@@ -1,5 +1,7 @@ {-# LANGUAGE NoPolyKinds #-} +{-# OPTIONS_HADDOCK not-home #-}+ module Polysemy.Internal.Lift where
src/Polysemy/Internal/NonDet.hs view
@@ -2,6 +2,8 @@ {-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE NoPolyKinds #-} +{-# OPTIONS_HADDOCK not-home #-}+ module Polysemy.Internal.NonDet where ------------------------------------------------------------------------------
+ src/Polysemy/Internal/PluginLookup.hs view
@@ -0,0 +1,9 @@+-- | Due to a quirk of the GHC plugin interface, it's only easy to find+-- transitive dependencies if they define an orphan instance. This module+-- exists to provide some things so we can define a (safe) orphan instance in+-- the module we want to find ("Polysemy.Internal").+module Polysemy.Internal.PluginLookup where++class PluginLookup t+data Plugin+
src/Polysemy/Internal/TH/Effect.hs view
@@ -2,6 +2,8 @@ {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TupleSections #-} +{-# OPTIONS_HADDOCK not-home #-}+ -- Originally ported from code written by Sandy Maguire (@isovector), available -- at https://github.com/IxpertaSolutions/freer-effects/pull/28.
src/Polysemy/Internal/TH/Performance.hs view
@@ -1,6 +1,8 @@ {-# LANGUAGE BlockArguments #-} {-# LANGUAGE TemplateHaskell #-} +{-# OPTIONS_HADDOCK not-home #-}+ module Polysemy.Internal.TH.Performance ( inlineRecursiveCalls ) where
src/Polysemy/Internal/Tactics.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE AllowAmbiguousTypes #-}-{-# LANGUAGE QuantifiedConstraints #-}++{-# OPTIONS_HADDOCK not-home #-} module Polysemy.Internal.Tactics ( Tactics (..)
src/Polysemy/Internal/Union.hs view
@@ -3,11 +3,12 @@ {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE QuantifiedConstraints #-} {-# LANGUAGE StrictData #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-} +{-# OPTIONS_HADDOCK not-home #-}+ module Polysemy.Internal.Union ( Union (..) , Yo (..)@@ -29,7 +30,7 @@ import Data.Functor.Compose import Data.Functor.Identity-import Data.Typeable+import Data.Type.Equality import Polysemy.Internal.Effect #ifdef ERROR_MESSAGES@@ -78,14 +79,8 @@ {-# INLINE liftYo #-} -instance (Functor m) => Functor (Union r m) where+instance Functor (Union r m) where fmap f (Union w t) = Union w $ fmap' f t- where- -- This is necessary to delay the interaction between the type family- -- 'IndexOf' and the quantified superclass constraint on 'Effect'.- fmap' :: (Functor m, Effect f) => (a -> b) -> f m a -> f m b- fmap' = fmap- {-# INLINE fmap' #-} {-# INLINE fmap #-} @@ -111,29 +106,28 @@ ) -data Dict c where Dict :: c => Dict c---induceTypeable :: SNat n -> Dict (Typeable n)-induceTypeable SZ = Dict-induceTypeable (SS _) = Dict-{-# INLINE induceTypeable #-}-- ------------------------------------------------------------------------------ -- | The kind of type-level natural numbers. data Nat = Z | S Nat- deriving Typeable ------------------------------------------------------------------------------ -- | A singleton for 'Nat'. data SNat :: Nat -> * where SZ :: SNat 'Z- SS :: Typeable n => SNat n -> SNat ('S n)- deriving Typeable+ SS :: SNat n -> SNat ('S n) +instance TestEquality SNat where+ testEquality SZ SZ = Just Refl+ testEquality (SS _) SZ = Nothing+ testEquality SZ (SS _) = Nothing+ testEquality (SS n) (SS m) =+ case testEquality n m of+ Nothing -> Nothing+ Just Refl -> Just Refl+ {-# INLINE testEquality #-} + type family IndexOf (ts :: [k]) (n :: Nat) :: k where IndexOf (k ': ks) 'Z = k IndexOf (k ': ks) ('S n) = IndexOf ks n@@ -147,7 +141,7 @@ Found (u ': ts) t = 'S (Found ts t) -class Typeable (Found r t) => Find (r :: [k]) (t :: k) where+class Find (r :: [k]) (t :: k) where finder :: SNat (Found r t) instance {-# OVERLAPPING #-} Find (t ': z) t where@@ -189,9 +183,7 @@ ------------------------------------------------------------------------------ -- | Weaken a 'Union' so it is capable of storing a new sort of effect. weaken :: Union r m a -> Union (e ': r) m a-weaken (Union n a) =- case induceTypeable n of- Dict -> Union (SS n) a+weaken (Union n a) = Union (SS n) a {-# INLINE weaken #-} @@ -209,12 +201,11 @@ ) => Union r m a -> Maybe (Yo e m a)-prj (Union (s :: SNat n) a) =- case induceTypeable s of- Dict ->- case eqT @n @(Found r e) of- Just Refl -> Just a+prj (Union sn a) =+ let sm = finder @_ @r @e+ in case testEquality sn sm of Nothing -> Nothing+ Just Refl -> Just a {-# INLINE prj #-}
src/Polysemy/State.hs view
@@ -14,11 +14,19 @@ , runState , runLazyState , runStateInIORef++ -- * Interoperation with MTL+ , hoistStateIntoStateT ) where -import Data.IORef-import Polysemy-import Polysemy.Internal.Combinators+import qualified Control.Monad.Trans.State as S+import Data.IORef+import Data.Tuple (swap)+import Polysemy+import Polysemy.Internal+import Polysemy.Internal.Combinators+import Polysemy.Internal.Effect+import Polysemy.Internal.Union ------------------------------------------------------------------------------@@ -80,6 +88,32 @@ Get -> sendM $ readIORef ref Put s -> sendM $ writeIORef ref s {-# INLINE runStateInIORef #-}+++------------------------------------------------------------------------------+-- | Hoist a 'State' effect into a 'S.StateT' monad transformer. This can be+-- useful when writing interpreters that need to interop with MTL.+--+-- @since 0.1.3.0+hoistStateIntoStateT+ :: Sem (State s ': r) a+ -> S.StateT s (Sem r) a+hoistStateIntoStateT (Sem m) = m $ \u ->+ case decomp u of+ Left x -> S.StateT $ \s ->+ liftSem . fmap swap+ . weave (s, ())+ (\(s', m') -> fmap swap+ $ S.runStateT m' s')+ $ hoist hoistStateIntoStateT_b x+ Right (Yo Get z _ y) -> fmap (y . (<$ z)) $ S.get+ Right (Yo (Put s) z _ y) -> fmap (y . (<$ z)) $ S.put s+{-# INLINE hoistStateIntoStateT #-}+++hoistStateIntoStateT_b :: Sem (State s ': r) a -> S.StateT s (Sem r) a+hoistStateIntoStateT_b = hoistStateIntoStateT+{-# NOINLINE hoistStateIntoStateT_b #-} {-# RULES "runState/reinterpret"
test/FusionSpec.hs view
@@ -43,7 +43,7 @@ shouldSucceed $(inspectTest $ 'jank `doesNotUse` 'reinterpret) shouldSucceed $(inspectTest $ 'jank `doesNotUse` 'hoist) - it "who needs Sematic even?" $ do+ it "who needs Semantic even?" $ do shouldSucceed $(inspectTest $ 'countDown `doesNotUse` 'Sem) shouldSucceed $(inspectTest $ 'jank `doesNotUse` 'Sem) shouldSucceed $(inspectTest $ 'tryIt `doesNotUse` 'Sem)