I am trying to use the State monad to do some computations while also altering it. I have implemented the instances of Applicative
, Monad
and Functor
as well as get
and put
,modify
, etc.
I do not understand the desugaring of the do
block. How do you supply both the state and the state transformer?
Utils
get::State s s
get=State $ \s ->(s,s)
put::s->State s ()
put x=State $ \_ -> ((),x)
modify::(s->s)->State s ()
modify f=get>>= \x -> put (f x)
evalState::State s a->s->a
evalState act =fst . run act
execState::State s a->s->s
execState act=snd.run act
Code
module Env where
import State
import System.Directory
import Control.Monad
data Env=Env{
envName::String,
fileNames::[String]
}
instance Show Env where
show Env{envName=x,fileNames=xs} = "{ envName:"++x++" , files: ["++foldr (\t y-> t++","++y) "" xs ++"] }"
initEnv::IO Env
initEnv=do
name<- getLine
names<- getCurrentDirectory>>=listDirectory
return Env{envName=name,fileNames=names}
changeName::String->State Env ()
changeName (y:ys)=State $ \ (Env (x:xs) ls) -> ((),Env (y:xs) ls)
toStats::State Env String
toStats= State $ \env -> (show env,env)
useEnv::IO (State Env String)
useEnv=do
liftM put initEnv --passes state transformer
liftM changeName getLine --passes strate transformer
print . evalState . toStats --how do i supply both ?
return toStats
As you can see, in my last line I am initializing the state transformer and passing it for further altering... until i reach evalState
and I want to use it. In this case i do not know how to supply the state and the transformer.
P.S By transformer i mean the wrapper over the s->(a,s)
Your code doesn't use any monad transformers. I think you're just looking for
useEnv :: IO ()
useEnv = do
env <- initEnv
name <- getLine
let actions = do
changeName name
toStats
let str = evalState actions env
putStrLn str
i.e. run the State
actions from inside an IO
do block.