packages feed

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 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)++-}