我正在查看State Monad' 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])
在get
的类型签名中:MonadState s m => m s
,[1,2,3]
的类型如何MonadState s m
?我不清楚s
和m
的类型是什么。
另外,您能否详细说明如何使用put
?
ghci的> :t put put :: MonadState s m => s - > m()
总的来说,似乎我不明白MonadState s m
是什么。您可以通过put
和get
示例解释一下吗?
答案 0 :(得分:8)
MonadState s m
是类型类约束,而不是类型。签名:
get :: MonadState s m => m s
对于某些monad m
存储某种类型s
的状态,get
是m
中的一个操作,它返回s
类型的值。这是非常抽象的,所以让我们使用来自transformers
的State
的重载较少的版本来使其更具体:
get :: State s s
put :: s -> State s ()
现在说我们想用State
来保持一个简单的计数器。我们使用execState
代替runState
,这样我们就可以关注状态的最终值。我们可以get
计数器的值:
> execState get 0
0
我们可以使用put
设置计数器的值:
> execState (put 1) 0
1
我们可以多次设置状态:
> execState (do put 1; put 2) 0
2
我们可以根据当前值修改状态:
> execState (do x <- get; put (x + 1)) 0
1
get
和put
的这种组合通常足以拥有自己的名称modify
:
> execState (do modify (+ 1)) 0
1
> execState (do modify (+ 2); modify (* 5)) 0
10
MonadState
是具有状态的monad类型。 State
是该类的一个实例:
instance MonadState s (State s) where
get = Control.Monad.Trans.State.get
put = Control.Monad.Trans.State.put
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
答案 1 :(得分:1)
在get的类型签名中:MonadState s m =&gt; m s,[1,2,3]如何 一种MonadState s m?我不清楚s和的类型是什么 我是。
ghci> runState get [1,2,3]
函数runState
有两个参数:第一个是要运行的State
动作,第二个是初始状态。因此,由于初始状态是[1,2,3]
,它是整数列表(*),因此状态类型s
只是[Integer]
。
(*)实际上,在GHCi默认之前[1,2,3] :: Num a => [a]
,但为了简单起见,让我们像GHCi一样使用[Integer]
。
因此,我们发现runState
专门用于
runState :: State [Integer] a -> [Integer] -> (a, [Integer])
现在,关于第一个论点:
get :: MonadState s m => m s
我们必须m s = State s a
,因为我们将其传递给需要此类型的runState
。因此:
runState :: State [Integer] a -> [Integer] -> (a, [Integer])
get :: MonadState s m => m s
with m s = State [Integer] a
后一个等式可以简化如下:
runState :: State [Integer] a -> [Integer] -> (a, [Integer])
get :: MonadState s m => m s
with m = State [Integer]
and s = a
代替s
:
runState :: State [Integer] a -> [Integer] -> (a, [Integer])
get :: MonadState a m => m a
with m = State [Integer]
代替m
:
runState :: State [Integer] a -> [Integer] -> (a, [Integer])
get :: MonadState a (State [Integer]) => State [Integer] a
现在,只有在MonadState a (State [Integer])
时才会满足约束a = [Integer]
。这很难看,因为MonasState
类型类利用函数依赖来强制该类中的每个monad只有一个相关的状态类型。从State
作为StateT
的包装,这也变得更加复杂。无论如何,我们得到:
runState :: State [Integer] a -> [Integer] -> (a, [Integer])
get :: MonadState a (State [Integer]) => State [Integer] a
with a = [Integer]
所以,
runState :: State [Integer] [Integer] -> [Integer] -> ([Integer], [Integer])
get :: MonadState [Integer] (State [Integer]) => State [Integer] [Integer]
由于满足约束条件:
runState :: State [Integer] [Integer] -> [Integer] -> ([Integer], [Integer])
get :: State [Integer] [Integer]
现在我们可以看到所涉及的地面类型。