State的`put`和`get`函数

时间:2014-08-22 02:05:11

标签: haskell

我正在查看State Monad' putget

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?我不清楚sm的类型是什么。

另外,您能否详细说明如何使用put

ghci的> :t put put :: MonadState s m => s - > m()

总的来说,似乎我不明白MonadState s m是什么。您可以通过putget示例解释一下吗?

2 个答案:

答案 0 :(得分:8)

MonadState s m是类型类约束,而不是类型。签名:

get :: MonadState s m => m s

对于某些monad m存储某种类型s的状态,getm中的一个操作,它返回s类型的值。这是非常抽象的,所以让我们使用来自transformersState的重载较少的版本来使其更具体:

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

getput的这种组合通常足以拥有自己的名称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]

现在我们可以看到所涉及的地面类型。