multistate (empty) → 0.1.1
raw patch · 8 files changed
+730/−0 lines, 8 filesdep +basedep +mtldep +multistatesetup-changed
Dependencies added: base, mtl, multistate, tfp, transformers
Files
- LICENSE +26/−0
- Setup.hs +2/−0
- example/Example.hs +56/−0
- multistate.cabal +97/−0
- src/Control/Monad/MultiReader.hs +172/−0
- src/Control/Monad/MultiState.hs +146/−0
- src/Data/HList/HList.hs +24/−0
- test/Test.hs +207/−0
+ LICENSE view
@@ -0,0 +1,26 @@+Copyright 2013-2014 Jan Bracker, Lennart Spitzner.+All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright notice,+ this list of conditions and the following disclaimer.+ * Redistributions in binary form must reproduce the above copyright+ notice, this list of conditions and the following disclaimer in the+ documentation and/or other materials provided with the distribution.+ * The names of this library's contributors may not be used to endorse or+ promote products derived from this software without specific prior+ written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE+POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ example/Example.hs view
@@ -0,0 +1,56 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TypeFamilies #-}++module Main where++++import Control.Monad.MultiState++import Control.Applicative ( (<$>), (<*>) )++import Control.Monad.Trans ( lift )++{-+Small example showing+ 1) a MultiState containing a Char and a [Char],+ 2) the polymorphic mGet,+ 3) how to initially put values into the MultiState using withMultiState,+ 4) the type inference at work - note that we omitted all type signatures.+-}++--examplePrint :: MultiStateT (Cons [Char] (Cons Char Null)) IO ()+-- or more general:+--examplePrint :: ( MonadMultiState [Char] m+-- , MonadMultiState Char m+-- , m~MultiStateT x IO)+-- => m ()+examplePrint = do+ c <- mGet+ cs <- mGet+ lift $ putStrLn (c:cs)++exampleAction = do+ examplePrint+ mSet 'J'+ examplePrint++main = evalMultiStateT+ $ withMultiState 'H'+ $ withMultiState "ello, World!"+ $ exampleAction++-- output of main:+-- "Hello, World!+-- Jello, World!+-- "++--whatIsNotPossible :: MultiStateT (Cons [Char] Null) IO ()+--whatIsNotPossible = mGet >>= (lift . print) -- type ambiguous++-- another thing that is not directly possible is the restriction to+-- specific values, i.e. a function+-- restrict :: MultiStateT xvalues m a -> MultiStateT yvalues m a+-- where yvalues is a "superset" of xvalues.++--TODO: example with mGetRaw and withMultiStates
+ multistate.cabal view
@@ -0,0 +1,97 @@+Name: multistate+Version: 0.1.1+Cabal-Version: >= 1.8+Build-Type: Simple+license: BSD3+license-file: LICENSE+Copyright: Jan Bracker, Lennart Spitzner+Maintainer: Lennart Spitzner <lsp@informatik.uni-kiel.de>+Author: Jan Bracker, Lennart Spitzner+Homepage: https://github.com/lspitzner/multistate+Bug-reports: https://github.com/lspitzner/multistate/issues+Stability: Experimental+category: Control+tested-with: GHC == 7.8.2++Synopsis: like mtl's ReaderT/StateT, but more than one contained value/type.+Description:+ When using multiple ReaderT's or StateT's in the same monad stack, it becomes+ necessary to lift the operations in order to affect a specific transformer.+ Using heterogenous lists (type level functions), a GADT and a corresponding+ type class, this package provides transformers that remove that necessity:+ MultiReaderT/MultiStateT can contain a heterogenous list of values.+ The type inferred for the getter/setter determines which value is+ read/written.+ See the Example application for some very basic usage.+ This package currently lacks a complete set of "lifting instances", i.e.+ instance definitions for classes such as mtl's MonadReader "over" the newly+ introduced monad transformers. These "lifting instances" would be necessary+ to achieve full compatability with existing transformers. Ping me if you+ find anything specific missing.++source-repository head+ type: git+ location: git@github.com:lspitzner/multistate.git++flag build-test+ description: Build the MultiState-test test program+ default: False++flag build-example+ description: Build the MultiState-example example program+ default: False ++library {+ exposed-modules:+ Control.Monad.MultiState+ Control.Monad.MultiReader+ other-modules:+ Data.HList.HList+ build-depends:+ base >=4 && <6,+ mtl >=2 && <3,+ tfp >=0.8,+ transformers == 0.3.*+ extensions:+ GADTs+ TypeFamilies+ MultiParamTypeClasses+ FunctionalDependencies+ FlexibleInstances+ OverlappingInstances+ UndecidableInstances+ ghc-options: -Wall+ hs-source-dirs: src+}++executable multistate-test {+ if flag(build-test) {+ buildable: True+ build-depends:+ multistate,+ base >= 4 && < 6,+ transformers == 0.3.*,+ tfp >=0.8+ } else {+ buildable: False+ }+ ghc-options: -Wall+ main-is: Test.hs+ hs-source-dirs: test+}++executable multistate-example {+ if flag(build-example) {+ buildable: True+ build-depends:+ multistate,+ base >= 4 && < 6,+ transformers == 0.3.*,+ tfp >=0.8,+ mtl >=2 && <3+ } else {+ buildable: False+ }+ main-is: Example.hs+ hs-source-dirs: example+}
+ src/Control/Monad/MultiReader.hs view
@@ -0,0 +1,172 @@+{-# LANGUAGE GADTs #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE OverlappingInstances #-}+{-# LANGUAGE UndecidableInstances #-}++module Control.Monad.MultiReader+ ( MultiReaderT(..)+ , MultiReaderTNull+ , MultiReader+ , MonadMultiReader(..)+ , mAskRaw+ , withMultiReader+ , withMultiReaders+ , evalMultiReaderT+ , evalMultiReaderTWithInitial+ , mapMultiReaderT+ , Cons -- re-export that stuff to allow writing type signatures.+ , Null+) where++++import Data.HList.HList++import Control.Monad.State.Strict ( StateT(..)+ , MonadState(..)+ , evalStateT+ , mapStateT )+import Control.Monad.Trans.Class ( MonadTrans+ , lift )+import Control.Monad.Writer.Class ( MonadWriter+ , listen+ , tell+ , writer+ , pass )++import Types.Data.List ( Cons+ , Null+ , Append )+import Data.Functor.Identity ( Identity )++import Control.Applicative ( Applicative(..) )+import Control.Monad ( liftM+ , ap )++++newtype MultiReaderT x m a = MultiReaderT {+ runMultiReaderTRaw :: StateT (HList x) m a+}++type MultiReaderTNull = MultiReaderT Null++type MultiReader x a = MultiReaderT x Identity a++class ContainsType a c where+ setHListElem :: a -> HList c -> HList c+ getHListElem :: HList c -> a++class (Monad m) => MonadMultiReader a m where+ mAsk :: m a++{-+it might make seem straightforward to define the following class that+corresponds to other transformer classes. But while we can define the the+class and its instances, there is a problem we try to use it, assuming that we+do not want to annotate the full type signature of the config:+ the type of the config can not be inferred properly. we would need a feature+ like "infer, as return type for this function, the only type for+ which there exists a valid chain of instance definitions that is needed to+ by this function".+ In other words, it is impossible to use the mAskRaw function without+ binding a concrete type for c, because otherwise the inference runs into+ some overlapping instances.+For this reason, I removed this type class and created a non-class function+mAskRaw, for which the type inference works because it involves no+type classes.+ lennart spitzner+-}++--class (Monad m) => MonadMultiReaderRaw c m where+-- mAskRaw :: m (HList c)++--instance (MonadTrans t, Monad (t m), MonadMultiReaderRaw c m)+-- => MonadMultiReaderRaw c (t m) where+-- mAskRaw = lift $ mAskRaw++--instance (Monad m) => MonadMultiReaderRaw a (MultiReaderT a m) where+-- mAskRaw = MultiReaderT $ get++instance ContainsType a (Cons a xs) where+ setHListElem a (TCons _ xs) = TCons a xs+ getHListElem (TCons x _) = x++instance (ContainsType a xs) => ContainsType a (Cons x xs) where+ setHListElem a (TCons x xs) = TCons x $ setHListElem a xs+ getHListElem (TCons _ xs) = getHListElem xs++instance (Functor f) => Functor (MultiReaderT x f) where+ fmap f = MultiReaderT . fmap f . runMultiReaderTRaw++instance (Applicative m, Monad m) => Applicative (MultiReaderT x m) where+ pure = MultiReaderT . pure+ (<*>) = ap++instance Monad m => Monad (MultiReaderT x m) where+ return = MultiReaderT . return+ k >>= f = MultiReaderT $ runMultiReaderTRaw k >>= (runMultiReaderTRaw.f)++instance MonadTrans (MultiReaderT x) where+ lift = MultiReaderT . lift++withMultiReader :: Monad m+ => x+ -> MultiReaderT (Cons x xs) m a+ -> MultiReaderT xs m a+withMultiReader x k = MultiReaderT $ do+ s <- get+ (a, TCons _ s') <- lift $ runStateT (runMultiReaderTRaw k) (TCons x s)+ put s'+ return a++withMultiReaders :: Monad m+ => HList xs+ -> MultiReaderT (Append xs ys) m a+ -> MultiReaderT ys m a+withMultiReaders TNull = id+withMultiReaders (TCons x xs) = withMultiReaders xs . withMultiReader x++instance (Monad m, ContainsType a c)+ => MonadMultiReader a (MultiReaderT c m) where+ mAsk = MultiReaderT $ liftM getHListElem get++instance (MonadTrans t, Monad (t m), MonadMultiReader a m)+ => MonadMultiReader a (t m) where+ mAsk = lift $ mAsk++mAskRaw :: Monad m => MultiReaderT a m (HList a)+mAskRaw = MultiReaderT get++evalMultiReaderT :: Monad m => MultiReaderT Null m a -> m a+evalMultiReaderT k = evalStateT (runMultiReaderTRaw k) TNull++evalMultiReaderTWithInitial :: Monad m+ => HList a+ -> MultiReaderT a m b+ -> m b+evalMultiReaderTWithInitial c k = evalStateT (runMultiReaderTRaw k) c++mapMultiReaderT :: (m (a, HList w)+ -> m' (a', HList w))+ -> MultiReaderT w m a+ -> MultiReaderT w m' a'+mapMultiReaderT f = MultiReaderT . mapStateT f . runMultiReaderTRaw++-- foreign lifting instances++instance (MonadState s m) => MonadState s (MultiReaderT c m) where+ put = lift . put+ get = lift $ get+ state = lift . state++instance (MonadWriter w m) => MonadWriter w (MultiReaderT c m) where+ writer = lift . writer+ tell = lift . tell+ listen = MultiReaderT .+ mapStateT (liftM (\((a,w), w') -> ((a, w'), w)) . listen) .+ runMultiReaderTRaw+ pass = MultiReaderT .+ mapStateT (pass . liftM (\((a, f), w) -> ((a, w), f))) .+ runMultiReaderTRaw
+ src/Control/Monad/MultiState.hs view
@@ -0,0 +1,146 @@+{-# LANGUAGE GADTs #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE OverlappingInstances #-}+{-# LANGUAGE UndecidableInstances #-}++module Control.Monad.MultiState+ ( MultiStateT(..)+ , MultiStateTNull+ , MultiState+ , MonadMultiState(..)+ , mGetRaw+ , withMultiState+ , withMultiStates+ , evalMultiStateT+ , evalMultiStateTWithInitial+ , mapMultiStateT+ , Cons -- re-export that stuff to allow writing type signatures.+ , Null+) where++++import Data.HList.HList++import Control.Monad.State.Strict ( StateT(..)+ , MonadState(..)+ , evalStateT+ , mapStateT )+import Control.Monad.Trans.Class ( MonadTrans+ , lift )+import Control.Monad.Writer.Class ( MonadWriter+ , listen+ , tell+ , writer+ , pass )++import Types.Data.List ( Cons+ , Null+ , Append )+import Data.Functor.Identity ( Identity )++import Control.Applicative ( Applicative(..) )+import Control.Monad ( liftM+ , ap )++++newtype MultiStateT x m a = MultiStateT {+ runMultiStateTRaw :: StateT (HList x) m a+}++type MultiStateTNull = MultiStateT Null++type MultiState x a = MultiStateT x Identity a++class ContainsType a c where+ setHListElem :: a -> HList c -> HList c+ getHListElem :: HList c -> a++class (Monad m) => MonadMultiState a m where+ mSet :: a -> m ()+ mGet :: m a++instance ContainsType a (Cons a xs) where+ setHListElem a (TCons _ xs) = TCons a xs+ getHListElem (TCons x _) = x++instance (ContainsType a xs) => ContainsType a (Cons x xs) where+ setHListElem a (TCons x xs) = TCons x $ setHListElem a xs+ getHListElem (TCons _ xs) = getHListElem xs++instance (Functor f) => Functor (MultiStateT x f) where+ fmap f = MultiStateT . fmap f . runMultiStateTRaw++instance (Applicative m, Monad m) => Applicative (MultiStateT x m) where+ pure = MultiStateT . pure+ (<*>) = ap++instance Monad m => Monad (MultiStateT x m) where+ return = MultiStateT . return+ k >>= f = MultiStateT $ runMultiStateTRaw k >>= (runMultiStateTRaw.f)++instance MonadTrans (MultiStateT x) where+ lift = MultiStateT . lift++withMultiState :: Monad m+ => x+ -> MultiStateT (Cons x xs) m a+ -> MultiStateT xs m a+withMultiState x k = MultiStateT $ do+ s <- get+ (a, TCons _ s') <- lift $ runStateT (runMultiStateTRaw k) (TCons x s)+ put s'+ return a++withMultiStates :: Monad m+ => HList xs+ -> MultiStateT (Append xs ys) m a+ -> MultiStateT ys m a+withMultiStates TNull = id+withMultiStates (TCons x xs) = withMultiStates xs . withMultiState x++instance (Monad m, ContainsType a c)+ => MonadMultiState a (MultiStateT c m) where+ mSet v = MultiStateT $ get >>= (put . setHListElem v)+ mGet = MultiStateT $ liftM getHListElem get++instance (MonadTrans t, Monad (t m), MonadMultiState a m)+ => MonadMultiState a (t m) where+ mSet = lift . mSet+ mGet = lift $ mGet++evalMultiStateT :: Monad m => MultiStateT Null m a -> m a+evalMultiStateT k = evalStateT (runMultiStateTRaw k) TNull++evalMultiStateTWithInitial :: Monad m+ => HList a+ -> MultiStateT a m b+ -> m b+evalMultiStateTWithInitial c k = evalStateT (runMultiStateTRaw k) c++mGetRaw :: Monad m => MultiStateT a m (HList a)+mGetRaw = MultiStateT get++mapMultiStateT :: (m (a, HList w) -> m' (a', HList w))+ -> MultiStateT w m a+ -> MultiStateT w m' a'+mapMultiStateT f = MultiStateT . mapStateT f . runMultiStateTRaw++-- foreign lifting instances++instance (MonadState s m) => MonadState s (MultiStateT c m) where+ put = lift . put+ get = lift $ get+ state = lift . state++instance (MonadWriter w m) => MonadWriter w (MultiStateT c m) where+ writer = lift . writer+ tell = lift . tell+ listen = MultiStateT .+ mapStateT (liftM (\((a,w), w') -> ((a, w'), w)) . listen) .+ runMultiStateTRaw+ pass = MultiStateT .+ mapStateT (pass . liftM (\((a, f), w) -> ((a, w), f))) .+ runMultiStateTRaw
+ src/Data/HList/HList.hs view
@@ -0,0 +1,24 @@+{-# LANGUAGE GADTs #-}+{-# LANGUAGE TypeFamilies #-}++module Data.HList.HList(+ HList(..)+) where++++import Prelude hiding (reverse)++import Types.Data.List ( Cons, Null )++++data HList a where+ TCons :: x -> HList xs -> HList (Cons x xs)+ TNull :: HList Null++instance Show (HList Null) where+ show _ = "()"++instance (Show a, Show (HList b)) => Show (HList (Cons a b)) where+ show (TCons x y) = "(" ++ show x ++ "," ++ show y ++ ")"
+ test/Test.hs view
@@ -0,0 +1,207 @@+module Main where++++import Data.Functor.Identity+import qualified Control.Monad.MultiState as MS+import qualified Control.Monad.MultiReader as MR+import Types.Data.List ( Cons, Null )++import Control.Applicative ( Applicative, (<$>), (<*>) )++++type Tests = [(Bool, String)]++runEvalMS :: MS.MultiStateT Null Identity a -> a+runEvalMS = runIdentity . MS.evalMultiStateT+runEvalMR :: MR.MultiReaderT Null Identity a -> a+runEvalMR = runIdentity . MR.evalMultiReaderT++runnerMS :: a -> MS.MultiStateT (Cons a Null) Identity a -> a+runnerMS x m = runIdentity $ MS.evalMultiStateT $ MS.withMultiState x m+runnerMR :: a -> MR.MultiReaderT (Cons a Null) Identity a -> a+runnerMR x m = runIdentity $ MR.evalMultiReaderT $ MR.withMultiReader x m++runnerMS_ :: a -> MS.MultiStateT (Cons a Null) Identity b -> a+runnerMS_ x m = runIdentity+ $ MS.evalMultiStateT+ $ MS.withMultiState x (m >> MS.mGet)+runnerMR_ :: a -> MR.MultiReaderT (Cons a Null) Identity b -> a+runnerMR_ x m = runIdentity+ $ MR.evalMultiReaderT+ $ MR.withMultiReader x (m >> MR.mAsk)++intRunnerMS :: Int -> MS.MultiStateT (Cons Int Null) Identity Int -> Int+intRunnerMS = runnerMS+intRunnerMS_ :: Int -> MS.MultiStateT (Cons Int Null) Identity b -> Int+intRunnerMS_ = runnerMS_+intRunnerMR :: Int -> MR.MultiReaderT (Cons Int Null) Identity Int -> Int+intRunnerMR = runnerMR+intRunnerMR_ :: Int -> MR.MultiReaderT (Cons Int Null) Identity b -> Int+intRunnerMR_ = runnerMR_++mrAskTuple :: ( Applicative m+ , MR.MonadMultiReader a m+ , MR.MonadMultiReader b m)+ => m (a,b)+mrAskTuple = (,) <$> MR.mAsk <*> MR.mAsk+msGetTuple :: ( Applicative m+ , MS.MonadMultiState a m+ , MS.MonadMultiState b m)+ => m (a,b)+msGetTuple = (,) <$> MS.mGet <*> MS.mGet++testsMultiState :: Tests+testsMultiState =+ [+ (1 == runIdentity (Identity (1::Int))+ , "identity"),+ (2 == intRunnerMS_ 2 (return ())+ , "multistate getConfig"),+ (3 == intRunnerMS_ 100 (MS.mSet (3::Int))+ , "multistate setConfig"),+ (4 == intRunnerMS_ 4 (MS.mGet >>= \x -> MS.mSet (x::Int))+ , "multistate setConfig"),+ (5 == intRunnerMS (4::Int) (MS.withMultiState (5::Int) MS.mGet)+ , "multistate nesting"),+ (6 == intRunnerMS (4::Int) ( MS.mSet (100::Int)+ >> MS.withMultiState (6::Int) MS.mGet)+ , "multistate nesting"),+ (7 == intRunnerMS (4::Int) ( MS.withMultiState (100::Int)+ $ MS.mSet (7::Int)+ >> MS.mGet)+ , "multistate nesting"),+ ((True, 'a') == ( runEvalMS+ $ MS.withMultiState True+ $ MS.withMultiState 'a'+ $ msGetTuple )+ , "multistate multiple types"),+ ((True, 'b') == ( runEvalMS+ $ MS.withMultiState True+ $ MS.withMultiState 'a'+ $ MS.withMultiState 'b'+ $ msGetTuple )+ , "multistate multiple types"),+ ((False, 'a') == ( runEvalMS+ $ MS.withMultiState True+ $ MS.withMultiState 'a'+ $ MS.withMultiState False+ $ msGetTuple )+ , "multistate multiple types"),+ (test13MS+ , "askRaw")+ ]++testsMultiReader :: Tests+testsMultiReader =+ [+ (1 == runIdentity (Identity (1::Int))+ , "identity"),+ (2 == intRunnerMR_ 2 (return ())+ , "multistate getConfig"),+ (5 == intRunnerMR (4::Int) (MR.withMultiReader (5::Int) MR.mAsk)+ , "multistate nesting"),+ ((True, 'a') == ( runEvalMR+ $ MR.withMultiReader True+ $ MR.withMultiReader 'a'+ $ mrAskTuple )+ , "multistate multiple types"),+ ((True, 'b') == ( runEvalMR+ $ MR.withMultiReader True+ $ MR.withMultiReader 'a'+ $ MR.withMultiReader 'b'+ $ mrAskTuple )+ , "multistate multiple types"),+ ((False, 'a') == ( runEvalMR+ $ MR.withMultiReader True+ $ MR.withMultiReader 'a'+ $ MR.withMultiReader False+ $ mrAskTuple )+ , "multistate multiple types"),+ (test13MR+ , "getRaw")+ ]++tests :: Tests+tests = testsMultiState ++ testsMultiReader++test13MR :: Bool+test13MR = runIdentity+ $ MR.evalMultiReaderT+ $ MR.withMultiReader True+ $ MR.withMultiReader 'a'+ $ do+ c <- MR.mAskRaw+ return $ runIdentity+ $ MR.evalMultiReaderT+ $ MR.withMultiReaders c+ $ do+ b <- MR.mAsk+ return (b::Bool)++test13MS :: Bool+test13MS = runIdentity+ $ MS.evalMultiStateT+ $ MS.withMultiState True+ $ MS.withMultiState 'a'+ $ do+ c <- MS.mGetRaw+ return $ runIdentity+ $ MS.evalMultiStateT+ $ MS.withMultiStates c+ $ do+ b <- MS.mGet+ return (b::Bool)++main :: IO ()+main = do+ mapM_ (putStrLn . ("error: "++) . snd) $ filter (\(b, _) -> not b) tests+ putStrLn $ "ran "+ ++ show (length tests)+ ++ " tests (no further output = good)"+ return ()++{-++main = do+ evalStateT+ (evalMultiReaderT $ withConfig 'a' $ do+ x <- withConfig 'b' getConfig+ lift $ lift $ print (x::Char)+ y <- get+ lift $ lift $ print (y::Int)+ return ()+ )+ (1::Int)+ evalMultiReaderT $ withConfig 'a' $ evalStateT+ ( do+ x <- getConfig+ lift $ lift $ print (x::Char)+ y <- get+ lift $ lift $ print (y::Int)+ return ()+ )+ (1::Int)++main = do+ evalStateT+ (evalMultiStateT $ withConfig 'a' $ do+ x <- withConfig 'b' getConfig+ lift $ lift $ print (x::Char)+ y <- get+ lift $ lift $ print (y::Int)+ return ()+ )+ (1::Int)+ evalMultiStateT $ withConfig 'a' $ evalStateT+ ( do+ x <- getConfig+ lift $ lift $ print (x::Char)+ y <- get+ lift $ lift $ print (y::Int)+ return ()+ )+ (1::Int)++-}