如何使用 State Monad
How to use the State Monad
我已经问过一个关于理解状态 monad 的问题,但现在我觉得这个应该是不同的。
鉴于我实现了状态 monad,我希望我的 state
成为类似于 Environment
:
的数据结构
环境
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}
我不知道如何将此数据结构作为 State
集成到 State monad 中,以便能够更改环境的 name
、打印它或使用它。它可能看起来太宽泛,但没有完整的例子我无法理解它:
状态 monad 实现
newtype State s a = State {run::s->(a,s)}
instance Functor (State s) where
fmap=Control.Monad.liftM
instance Applicative (State s) where
pure=return
(<*>)=Control.Monad.ap
instance Monad (State s) where
return a= State $ \k->(a,k)
(>>=) m f=State $ \s -> let (a,s')=run m s in
run (f a) s'
我想实现什么
readEnv::State a Env->Env
readEnv m =
changeEnvName::State a Env->State a Env
changeEnvName m = --given the environment packed in a state ,
-- i want to change the name
getEnvFileLengths::State a Env->[Int]
getEnvFileLengths s a= s>>= getLengths
getLengths::[String]->[Int]
getLengths xs=map length xs
P.S 我知道我应该使用 Reader
或 Writer
monad 但我想要一个 all in one
方法能够理解所有事物是如何组合在一起的。
有什么想法吗?
如果类型签名正确,可能会更容易取得进展:
readEnv::State Env Env
changeEnvName::String -> State Env ()
getEnvFileLengths::State Env [Int]
如果您觉得这些类型的选择很奇怪,可能值得尝试扩展 newtype
并查看之后它们是否显得更合理:
-- give me an initial environment from your store, I'll give you the new environment
-- to store and another copy of the environment as the result of the computation
readEnv :: Env -> (Env, Env)
-- give me a new name and the old environment, I'll give you a new environment and
-- a trivial acknowledgement that I'm done
changeEnvName :: String -> Env -> ((), Env)
-- give me an initial environment that you're storing, I'll give you the new
-- environment to store (actually same as the old one) and the result of the
-- length computations
getEnvFileLengths :: Env -> ([Int], Env)
我已经问过一个关于理解状态 monad 的问题,但现在我觉得这个应该是不同的。
鉴于我实现了状态 monad,我希望我的 state
成为类似于 Environment
:
环境
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}
我不知道如何将此数据结构作为 State
集成到 State monad 中,以便能够更改环境的 name
、打印它或使用它。它可能看起来太宽泛,但没有完整的例子我无法理解它:
状态 monad 实现
newtype State s a = State {run::s->(a,s)}
instance Functor (State s) where
fmap=Control.Monad.liftM
instance Applicative (State s) where
pure=return
(<*>)=Control.Monad.ap
instance Monad (State s) where
return a= State $ \k->(a,k)
(>>=) m f=State $ \s -> let (a,s')=run m s in
run (f a) s'
我想实现什么
readEnv::State a Env->Env
readEnv m =
changeEnvName::State a Env->State a Env
changeEnvName m = --given the environment packed in a state ,
-- i want to change the name
getEnvFileLengths::State a Env->[Int]
getEnvFileLengths s a= s>>= getLengths
getLengths::[String]->[Int]
getLengths xs=map length xs
P.S 我知道我应该使用 Reader
或 Writer
monad 但我想要一个 all in one
方法能够理解所有事物是如何组合在一起的。
有什么想法吗?
如果类型签名正确,可能会更容易取得进展:
readEnv::State Env Env
changeEnvName::String -> State Env ()
getEnvFileLengths::State Env [Int]
如果您觉得这些类型的选择很奇怪,可能值得尝试扩展 newtype
并查看之后它们是否显得更合理:
-- give me an initial environment from your store, I'll give you the new environment
-- to store and another copy of the environment as the result of the computation
readEnv :: Env -> (Env, Env)
-- give me a new name and the old environment, I'll give you a new environment and
-- a trivial acknowledgement that I'm done
changeEnvName :: String -> Env -> ((), Env)
-- give me an initial environment that you're storing, I'll give you the new
-- environment to store (actually same as the old one) and the result of the
-- length computations
getEnvFileLengths :: Env -> ([Int], Env)