【问题标题】:Understanding the State Monad了解状态单子
【发布时间】:2019-12-13 21:28:57
【问题描述】:

我在“Learn You a Haskell for Great Good!”一书中学习了 State monad。米兰利波卡。 对于以下 monad 实例:

instance Monad (State s) where 
   return x = State $ \s -> (x,s)
   (State h) >>= f = State $ \s -> let (a, newState) = h s
                                       (State g) = f a
                                   in g newState

我无法理解>>= 函数的定义。我不确定h 是否是有状态计算(即接受状态并返回具有更新状态的结果的函数)或者它是否是状态。我猜它一定是有状态的计算,因为它被应用于 lambda 函数中的状态(s 类型)以产生结果(a, newState)

但是从State s a的类型声明来看:

newtype State s a = State { runState :: s -> (a,s) }

状态为s 类型,结果为a 类型。那么对于 monad 实例,instance Monad (State s) 中的 s 是状态的 type 还是实际上是有状态的计算?任何见解都值得赞赏。

【问题讨论】:

  • 在一本面向新手的书中,使用 newtype {- StatePassingComputations -} State s a = MkState { runState :: s -> (a,s) } 可能不会那么混乱。

标签: haskell functional-programming monads state-monad newtype


【解决方案1】:

State 对象存储状态。它存储“状态变化”。实际上它存储了一个函数runState :: s -> (a, s)。这里s是状态的类型,a可以说是“输出”的类型。

因此,该函数将状态作为输入,并返回一个 2 元组 (a, s)。这里第一项是“输出”,第二项是“新状态”。新状态可能与旧状态相同,但因此有机会更改状态(否则无论如何使用State 并不是很有用)。

我们可以将State-sharing 对象和一个状态改变对象(a -&gt; State s b)的“工厂”绑定到一个新的State-changing 对象中。因此,我们构造了一个具有初始状态s<sub>0</sub> 的函数。我们首先将其运行到State 对象的runState,从而检索一个二元组(a, s<sub>1</sub>)。然后我们可以使用这个a 来构造一个State s b 对象,然后我们通过那个State 对象的runState 运行(改变的状态)s<sub>1</sub>

因此,更详细的实现是:

instance Monad (State s) where 
   return x = State $ \s -> (x,s)
   (State h) >>= f = State g
       where g s0 = (b, s2) -- result of second runState
                 where (a, s1) = h s0 -- run through first runState
                       -- create second state with the output of the first
                       State f' = f a
                       (b, s2) = f' s1 -- run through second runState

请注意,我们这里从来没有真正拥有一个状态值。我们只构建一个作用于该状态值的新函数。

从示意图上我们可以看到绑定运算符如下:

 s0
\ /
 | |
 | |
 ||||
  |\_________
  | '
  | s1
  v \ /
  一个 -----> | |
             | |
             ||||
              |\_______
              | '
              v s2
              b

所以这里第一个runState 采用初始状态s<sub>0</sub> 将返回as<sub>1</sub>。使用a,我们构造了一个新的runState,然后可以进一步处理状态s<sub>1</sub>,并返回一个b和新的状态s<sub>2</sub>

【讨论】:

    猜你喜欢
    • 2014-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-09
    • 2019-01-28
    相关资源
    最近更新 更多