I'n看国家单子的put和get:
ghci> :t get
get :: MonadState s m => m s
ghci> :t runState
runState :: State s a -> s -> (a, s)
ghci> runState get [1,2,3]
([1,2,3],[1,2,3])
Run Code Online (Sandbox Code Playgroud)
在get's类型签名:MonadState s m => m s,有怎样[1,2,3]的类型MonadState s m?目前尚不清楚对我有什么的类型s和m是.
另外,您能否详细说明如何使用put?
ghci>:t put put :: MonadState sm => s - > m()
总的来说,似乎我不明白是什么MonadState s m.你能解释一下put和get例子吗?
MonadState s m是类型类约束,而不是类型.签名:
get :: MonadState s m => m s
Run Code Online (Sandbox Code Playgroud)
说对于一些m存储某种类型状态的monad s,get是一个m返回类型值的动作s.这是非常抽象的,所以让我们使用较少重载的Statefrom transformers:
get :: State s s
put :: s -> State s ()
Run Code Online (Sandbox Code Playgroud)
现在说我们想用来State保持一个简单的计数器.让我们使用execState而不是runState这样我们可以只关注状态的最终值.我们可以get计数器的价值:
> execState get 0
0
Run Code Online (Sandbox Code Playgroud)
我们可以使用put以下方法设置计数器的值:
> execState (put 1) 0
1
Run Code Online (Sandbox Code Playgroud)
我们可以多次设置状态:
> execState (do put 1; put 2) 0
2
Run Code Online (Sandbox Code Playgroud)
我们可以根据其当前值修改状态:
> execState (do x <- get; put (x + 1)) 0
1
Run Code Online (Sandbox Code Playgroud)
的组合get和put足够常见的有自己的名称,modify:
> execState (do modify (+ 1)) 0
1
> execState (do modify (+ 2); modify (* 5)) 0
10
Run Code Online (Sandbox Code Playgroud)
MonadState是具有状态的monad类型.State是该类的一个实例:
instance MonadState s (State s) where
get = Control.Monad.Trans.State.get
put = Control.Monad.Trans.State.put
Run Code Online (Sandbox Code Playgroud)
所以StateT(状态monad变换器,它将状态添加到另一个monad)和其他各种.引入了这种重载,因此如果您使用的是monad变换器堆栈,则不需要lift在不同的变换器之间进行显式操作.如果你不这样做,你可以使用更简单的操作transformers.
这是另一个如何State用于封装变量映射的示例Data.Map:
import Control.Monad.Trans.State
import qualified Data.Map as M
action = do
modify (M.insert "x" 2) -- x = 2
modify (M.insert "y" 3) -- y = 3
x <- gets (M.! "x")
y <- gets (M.! "y")
modify (M.insert "z" (x + y)) -- z = x + y
modify (M.adjust (+ 2) "z") -- z += 2
gets (M.! "z") -- return z
main = do
let (result, vars) = execState action M.empty
putStr "Result: "
print result
putStr "Vars: "
print vars
Run Code Online (Sandbox Code Playgroud)