There are MonadTransControl and MonadBaseControl in the monad-control package, but what is the correct way to use them?
http://maoe.hatenadiary.jp/entry/20111207/1323185162
Simply put, the MonadTransControl class liftWith::Monadm=>(Run->ma)->
tma is the type m
that pop one monad stack tma
It has a role to play with a, and MonadBaseControl's liftBaseWith::(RunInBase mb->b
)
a) ->ma has a role to play with the base monad type ba that pops to the bottom of the stack.
It says, but both had to be lifted to the bottom.
Is MonadTransControl an aid in defining MonadBaseControl?
{-#LANGUAGE ScopedTypeVariables#-}
{-# LANGUAGE DeriveDataType#-}
{-# LANGUAGE FlexibleContexts#-}
{-# LANGUAGE FlexibleInstances#-}
{-# LANGUAGE GeneralizedNewtypeDeriving#-}
{-# LANGUAGE MultiParamTypeClasses#-}
{-# LANGUAGE StandaloneDeriving#-}
{-# LANGUAGE TypeFamilies#-}
{-# LANGUAGE UndecidableInstances#-}
import Control.Monad.Base
import Control.Monad.Reader
import Control.Monad.State
import Control.Applicative
import Control.Monad.Trans.Control
import Control.Monad.Identity
import Control.Monad.Except
import Control.Monad.Trans.Except
import Data.Maybe
import qualified Data.Map as Map
typeName = String
type Value = String
typeEnv = Map.MapNameValue
-- Inside the EvalR
newtypeEvalEma=EvalE{runEvalE::ExceptT Stringma}
deriving (Functor)
, Applicative
, Monad
, MonadError String
, MonadBase base
)
instanceMonadTransEvalEwhere
lift = EvalE.lift
instanceMonadTransControlEvalEwhere
type StT EvalEa = StT(ExceptT String)a
liftWith=defaultLiftWithEvalErunEvalE
restoreT=defaultRestoreTEvalE
instance(MonadBaseControl bm) =>MonadBaseControl b(EvalEm)where
typeStM(EvalEm)a=ComposeStEvalEma
liftBaseWith=defaultLiftBaseWith
restoreM=defaultRestoreM
evalET::(Monad(t[], MonadTransControlt) =>t[] Int
evalET = return1
EVALEM::(MonadBaseControl[] m) =>m Int
eventEM=return1
doEvalET::EvalE[] Int->EvalE[] Int
doEvalETt=liftWith(\run->run)>>=restoreT.return
doEvalEM::EvalE[] Int->EvalE[] Int
doEvalEMm=liftBaseWith(\run->runm)>>=restoreM
exEvalE::EvalE[] Int->IO()
exEvalE=print.runEvalE
exEvalET::EvalE[] Int->IO()
exEvalET=print.runEvalE.doEvalET
exEvalEM::EvalE[] Int->IO()
exEvalEM=print.runEvalE.doEvalEM
newtypeEvalRma=EvalR{runEvalR::ReaderTEnv(EvalEm)a}
deriving (Functor)
, Applicative
, Monad
, MonadError String
, MonadReader Env
, MonadBase base
)
instanceMonadTransEvalRwhere
lift = EvalR.lift.lift
-- I had to lift everything.
-- In fact, I picked up just one thing, and it turned out to be EvalE.
instanceMonadTransControlEvalRwhere
type StTEvalRa=StTEvalE(StT(ReaderTEnv)a)
liftWith=EvalR$liftWith$\runReader->
liftWith$\runEval->
f$runEval.runReader.runEvalR
restoreT=EvalR.restoreT.restoreT
instance(MonadBaseControl bm) =>MonadBaseControl b(EvalRm)where
typeStM(EvalRm)a=ComposeStEvalRma
liftBaseWith=defaultLiftBaseWith
restoreM=defaultRestoreM
env::Env
env=Map.fromList [("0", "zero"), (1", "one")]
doEvalRT::EvalR[]Int->EvalR[]Int
doEvalRTt=do
x<-liftWith$\r->
rt
restoreT$returnx
doEvalRM::EvalR[]Int->EvalR[]Int
doEvalRMm=liftBaseWith(\run->runm)>>=restoreM
exEvalR::EvalR[]Int->IO()
exEvalR=print.runEvalE.(flip runReaderTenv).runEvalR
exEvalRT::EvalR[]Int->IO()
exEvalRT=print.runEvalE.(flip runReaderTenv).runEvalR.doEvalRT
exEvalRM::EvalR[]Int->IO()
exEvalRM=print.runEvalE.(flip runReaderTenv).runEvalR.doEvalRM
Or is it possible to use the different types of tma and ma?
maybeTIO::(Monad(tIO), MonadTransControlt) =>t IO Int
maybeTIO=lift(putStrLn "testMaybeT")>>return1
maybeMIO::(MonadBaseControl IOm) =>m Int
maybeMIO=liftBase(putStrLn "testMaybeT")>>return1
twiceIO::IO a->IO a
twiceIO action=action>>action
testLiftWith::MaybeTIO Int ->MaybeTIO Int
testLiftWith=liftWith(\run->twiceIO(runf))>>=restoreT.return
testLiftBaseWith::MaybeTIO Int ->MaybeTIO Int
testLiftBaseWith=liftBaseWith(\run->twiceIO(runf))>>=restoreM
testControl::MaybeTIO Int->MaybeTIO Int
testControlf=control(\run->twiceIO(runmaybeTIO))
In the example presented, two layers of monad stack called MaybeTIO
are used, so MonadTransControl
and MonadBaseControl
are lifted the same, but using more than three layers of stack makes the difference.
The following example uses a three-tier stack called StateT Int (MaybeTIO)
.In this case, the testLiftBaseWith2
using MonadBaseControl
automatically lifts two tiers, so the testLiftBaseWith
code can be used as it is.On the other hand, in testLiftWith2
using MonadTransControl
, one liftWith
lifts only one tier and must be lifted twice explicitly.
testLiftWith2::StateT Int (MaybeTIO) Int->StateT Int (MaybeTIO) Int
testLiftWith2f=liftWith(\runState->liftWith(\runMaybe->twiceIO(runMaybe(runMaybe(runStatef))))>=restoreT.return)>=restoreT.return
testLiftBaseWith2::StateT Int (MaybeTIO) Int->StateT Int (MaybeTIO) Int
testLiftBaseWith2f = liftBaseWith(\run->twiceIO(runf))>>=restoreM
While MonadTrans
lifts only one layer, MonadIO
lifts the bottom layer of MonadIO
lifts the bottom layer of IO
(MonadBase
can also be used to generalize MonadI
).
© 2024 OneMinuteCode. All rights reserved.