has-transformers (empty) → 0.1.0.0
raw patch · 13 files changed
+290/−0 lines, 13 filesdep +basedep +has-transformersdep +hspec
Dependencies added: base, has-transformers, hspec, operational, transformers
Files
- CHANGELOG.md +5/−0
- LICENSE +20/−0
- examples/Examples/StateSig.hs +35/−0
- examples/Examples/TwoReaders.hs +30/−0
- examples/Examples/TwoReadersSpec.hs +11/−0
- examples/Spec.hs +1/−0
- has-transformers.cabal +65/−0
- src/Control/Monad/Trans/Has.hs +36/−0
- src/Control/Monad/Trans/Has/Accum.hs +17/−0
- src/Control/Monad/Trans/Has/Except.hs +18/−0
- src/Control/Monad/Trans/Has/Reader.hs +16/−0
- src/Control/Monad/Trans/Has/State.hs +19/−0
- src/Control/Monad/Trans/Has/Writer.hs +17/−0
+ CHANGELOG.md view
@@ -0,0 +1,5 @@+# Revision history for lift-transformers++## 0.1.0.0 -- YYYY-mm-dd++* First version. Released on an unsuspecting world.
+ LICENSE view
@@ -0,0 +1,20 @@+Copyright (c) 2021 Manuel Bärenz++Permission is hereby granted, free of charge, to any person obtaining+a copy of this software and associated documentation files (the+"Software"), to deal in the Software without restriction, including+without limitation the rights to use, copy, modify, merge, publish,+distribute, sublicense, and/or sell copies of the Software, and to+permit persons to whom the Software is furnished to do so, subject to+the following conditions:++The above copyright notice and this permission notice shall be included+in all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ examples/Examples/StateSig.hs view
@@ -0,0 +1,35 @@+module Examples.StateSig where++import "base" Control.Monad (when)++import "operational" Control.Monad.Operational++import "has-transformers" Control.Monad.Trans.Has+import "has-transformers" Control.Monad.Trans.Has.State++data StateSig s a where+ Put :: s -> StateSig s ()+ Get :: StateSig s s++type StateSigT s m a = ProgramT (StateSig s) m a++type HasStateSig s m = Has (ProgramT (StateSig s)) m++putS :: HasStateSig s m => s -> m ()+-- putS = liftH . singleton . Put+putS s = liftH $ singleton $ Put s++getS :: HasStateSig s m => m s+getS = liftH $ singleton Get++program :: (HasStateSig Bool m, Monad m) => m ()+program = do+ b <- getS+ when b $ putS False++interpretStateSig :: HasState s m => StateSig s a -> m a+interpretStateSig (Put s) = put s+interpretStateSig Get = get++interpretStateSigT :: (HasState s m, Monad m) => StateSigT s m a -> m a+interpretStateSigT = interpretWithMonadT interpretStateSig
+ examples/Examples/TwoReaders.hs view
@@ -0,0 +1,30 @@+module Examples.TwoReaders where++import "has-transformers" Control.Monad.Trans.Has.Reader++-- | Our "business logic" program using two 'ReaderT' effects.+-- Note that we use a type signature to help the type checker understand+-- which environment is which.+program ::+ (Monad m, HasReader Int m, HasReader Bool m) =>+ m (Int, Bool)+program = do+ envInt <- ask+ envBool <- ask+ return (envInt, envBool)++-- | The 'Int' environment we are going to supply+envInt :: Int+envInt = 23++-- | The 'Bool' environment we are going to supply+envBool :: Bool+envBool = True++-- | For documentation, this is the stack that will be handled.+-- (But we don't actually ever use this type alias.)+type Stack a = ReaderT Int (ReaderT Bool IO) a++-- | The 'program' with its environments supplied+handled :: IO (Int, Bool)+handled = program `runReaderT` envInt `runReaderT` envBool
+ examples/Examples/TwoReadersSpec.hs view
@@ -0,0 +1,11 @@+module Examples.TwoReadersSpec where++import "hspec" Test.Hspec++import Examples.TwoReaders++spec :: Spec+spec = do+ describe "two-Reader stack" $ do+ it "returns the environments" $ do+ handled `shouldReturn` (envInt, envBool)
+ examples/Spec.hs view
@@ -0,0 +1,1 @@+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
+ has-transformers.cabal view
@@ -0,0 +1,65 @@+cabal-version: 2.4+name: has-transformers+version: 0.1.0.0++synopsis: This library `Has` transformers++description:+ A very slim library for first-order effects based on monad transformers+ (and nearly nothing else).+ .+ Given a transformer stack @t1 (t2 (t3 (... m))) a@,+ you can automatically lift any function @thing :: tN m a@ into the stack with a single function, 'liftH'.++bug-reports: https://github.com/turion/has-transformers/issues+license: MIT+license-file: LICENSE+author: Manuel Bärenz+maintainer: programming@manuelbaerenz.de++copyright: (c) 2021- Manuel Bärenz+category: Effect+extra-source-files: CHANGELOG.md++library+ exposed-modules:+ Control.Monad.Trans.Has+ Control.Monad.Trans.Has.Accum+ Control.Monad.Trans.Has.Except+ Control.Monad.Trans.Has.Reader+ Control.Monad.Trans.Has.State+ Control.Monad.Trans.Has.Writer+ default-extensions:+ ConstraintKinds+ , FlexibleContexts+ , FlexibleInstances+ , ImportQualifiedPost+ , MultiParamTypeClasses+ , PackageImports+ build-depends:+ base ^>= 4.14.3.0+ , transformers+ hs-source-dirs: src+ default-language: Haskell2010++test-suite examples+ type: exitcode-stdio-1.0+ default-language: Haskell2010+ main-is: Spec.hs+ hs-source-dirs: examples+ other-modules:+ Examples.StateSig+ Examples.TwoReaders+ Examples.TwoReadersSpec+ default-extensions:+ ConstraintKinds+ , FlexibleContexts+ , GADTs+ , ImportQualifiedPost+ , PackageImports+ build-depends:+ base ^>= 4.14.3.0+ , has-transformers+ , hspec >= 2.9.0+ , operational+ build-tool-depends: hspec-discover:hspec-discover
+ src/Control/Monad/Trans/Has.hs view
@@ -0,0 +1,36 @@+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE KindSignatures #-}+module Control.Monad.Trans.Has where++import "transformers" Control.Monad.Trans.Class++-- |+-- class Has t m where+-- liftH :: t Identity a -> m a++{- | The transformer stack @m@ contains the transformer @t@.++Explicitly, @m = t1 (t2 (t3 ... (tN m)...))@,+and @t@ is one of these @t1, t2, ...@s.+-}+class Has (t :: (* -> *) -> * -> *) m where+ {- | Insert an action of this transformer into an arbitrary position in the stack.++ This will apply 'lift' as many times as necessary to insert the action.+ The higher-rank type involving @forall n@ basically says:+ "The action to lift must only use the structure of the _transformer_,+ not of a specific monad,+ and is thus definable for any monad @n@".+ -}+ liftH :: (forall n . Monad n => t n a) -> m a++-- | If the transformer is outermost,+-- the action can be inserted as-is.+instance Monad m => Has t (t m) where+ liftH = id+ {-# INLINE liftH #-}++-- | If the target transformer @t@ is under a different layer @t1@, 'lift' once.+instance {-# Overlappable #-} (Monad m, MonadTrans t1, Has t m) => Has t (t1 m) where+ liftH action = lift $ liftH action+ {-# INLINE liftH #-}
+ src/Control/Monad/Trans/Has/Accum.hs view
@@ -0,0 +1,17 @@+module Control.Monad.Trans.Has.Accum+ ( module Control.Monad.Trans.Has.Accum+ , module X+ ) where++import "transformers" Control.Monad.Trans.Accum+ qualified as Accum+import "transformers" Control.Monad.Trans.Accum+ as X+ (AccumT (..))++import "this" Control.Monad.Trans.Has++type HasAccum w m = Has (AccumT w) m++add :: HasAccum w m => w -> m ()+add w = liftH $ Accum.add w
+ src/Control/Monad/Trans/Has/Except.hs view
@@ -0,0 +1,18 @@+module Control.Monad.Trans.Has.Except+ ( module Control.Monad.Trans.Has.Except+ , module X+ ) where++import "transformers" Control.Monad.Trans.Except+ qualified as Except+import "transformers" Control.Monad.Trans.Except+ as X+ (ExceptT (..))++import "this" Control.Monad.Trans.Has+import qualified Control.Monad.Trans.Except as Control.Monad.Trans.Has++type HasExcept e m = Has (ExceptT e) m++throw :: HasExcept e m => e -> m ()+throw e = liftH $ ExceptT $ return $ Left e
+ src/Control/Monad/Trans/Has/Reader.hs view
@@ -0,0 +1,16 @@+module Control.Monad.Trans.Has.Reader+ ( module Control.Monad.Trans.Has.Reader+ , module X+ ) where++import "transformers" Control.Monad.Trans.Reader+ qualified as Reader+import "transformers" Control.Monad.Trans.Reader+ as X (ReaderT(..))++import "this" Control.Monad.Trans.Has++type HasReader r m = Has (ReaderT r) m++ask :: HasReader r m => m r+ask = liftH Reader.ask
+ src/Control/Monad/Trans/Has/State.hs view
@@ -0,0 +1,19 @@+module Control.Monad.Trans.Has.State+ ( module Control.Monad.Trans.Has.State+ , module X+ ) where++import "transformers" Control.Monad.Trans.State.Strict+ qualified as State+import "transformers" Control.Monad.Trans.State.Strict+ as X (StateT(..))++import "this" Control.Monad.Trans.Has++type HasState s m = Has (StateT s) m++get :: HasState s m => m s+get = liftH State.get++put :: HasState s m => s -> m ()+put s = liftH $ State.put s
+ src/Control/Monad/Trans/Has/Writer.hs view
@@ -0,0 +1,17 @@+module Control.Monad.Trans.Has.Writer+ ( module Control.Monad.Trans.Has.Writer+ , module X+ ) where++import "transformers" Control.Monad.Trans.Writer.Strict+ qualified as Writer+import "transformers" Control.Monad.Trans.Writer.Strict+ as X+ (WriterT (..))++import "this" Control.Monad.Trans.Has++type HasWriter w m = Has (WriterT w) m++tell :: HasWriter w m => w -> m ()+tell w = liftH $ Writer.tell w