【问题标题】:Understanding the state argument in the State Monad理解 State Monad 中的状态参数
【发布时间】:2019-05-20 13:17:15
【问题描述】:

我非常努力地围绕着 State Monad,但我不明白以下内容:

鉴于return(>>=)的实现,当你说State $ \s ->....时,s从何而来?我的意思是,当您开始执行>>= ... >>= 时,这是否意味着在链的开头某处您必须以某种方式提供该初始参数?

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

 instance Monad (State s) where
        return a=State $ \s->(a,s)
        (>>=) m g=State $ \s -> let (a,s')= runState m s in
                                   runState (g a) s'

(>>=) 你说State $ \s -> runState m s,我不明白什么时候是那个初始的(\s -> ...) argument(带有REAL argument)被调用?

谁能解释一下?

稍后编辑

谁能告诉我如何设置initial 状态,假设它是否需要使用getLine 获取值?

main::IO()
main=do
  argument<-getLine
  --how do i set initial state with argument?
  m >> f1 >> f2 >> f3

【问题讨论】:

  • 它是 initial 状态,因此可以创建函数,其中状态被传递(有时被修改)并传递到下一个状态。
  • 因此我们采用两种状态,并创建一个新的StateState 实际上不是状态,而是状态的change。因此,我们创建了一个新的状态更改,首先将s 传递给第一个,结果(a, s') 包含修改后的状态s',然后传递给下一个。
  • State s a 值视为“状态转换器”,这是一台可以修改状态的机器,当输入一个值时,它会在此过程中生成a 类型的值。当一个人最终决定使用runState myStateValue myInitialState 运行一元计算时,就会传递具体的、真实的初始状态。这是使用 monad 的典型工作流程:您使用大量 &gt;&gt;=/return 来构建 M a 类型的值,并在最后一步使用 runMM a 转换为一些可用类型,打破一元抽象。
  • 您在 IO do 块中写入 let x = runState st argument,或 runState (do { x &lt;- get ; return (x+1) }) 0。但这是一个新问题

标签: haskell monads state-monad


【解决方案1】:

当你说State $ \s -&gt;.... 时,s 来自哪里?

来自调用,当runState 将初始状态值提供给 state-monadic 值,以运行它描述的组合计算:

st = do { x <- get ; return (x+1) }

x = runState st 0    -- x is (1,0)

我还感觉到您可能存在另一个误解:您写道:“何时最初的(\s -&gt; ...) argument 被调用?”没有“初始”lambda:lambdas 都嵌套在里面!

do { a <- as; b <- bs; c <- foo b; return c }

翻译成

as >>= (\a -> bs >>= (\b -> foo b >>= (\c -> return c)))

所以它不是“初始”,它是一个组合的全封闭 lambda,以初始状态调用!

然后it会调用

let (a,s1) = runState as s0

等等。在do 块中使用“初始”as

【讨论】:

    【解决方案2】:

    do 块不执行任何有状态计算 - 它只是将一些较小的有状态计算组合成一个更大的有状态计算。在do 级别,实际状态不存在。

    如果将 monad 称为“有状态计算”,它会更简单,甚至可能更准确。或者“一个函数,它采用 S 类型的状态并返回另一个相同类型的状态及其实际结果”。那么你可以把&gt;&gt;=想象成“将上述类型的两个函数合二为一,将第一个返回的状态作为参数传递给第二个”。

    【讨论】:

    • 我更喜欢的措辞是,“do 块不执行,它描述计算要执行。” :)
    • @WillNess do 与任何其他函数没有什么不同:) 你会说find“描述在可折叠中找到一个值”还是你会说find“找到一个值在可折叠的“? :-)
    • do 与任何其他函数相当不同,即它根本不是函数。
    • find 的源代码确实描述了在 Foldable 中查找值;问题是它根本不是 Haskell 值。 do 块中的每一行(&lt;- 右侧的部分,如果存在)一个 Haskell 值。这就是区别。
    • @ReinHenrichs "find's source code is not a Haskell value" 是我的意思。
    【解决方案3】:

    State 只是 s -&gt; (a, s) 类型函数的封装。 runState 实际上并没有“运行”任何东西;它只是返回由State 构造函数包装的函数。但是,您可以将 runState($) 运算符进行比较以获得函数。

    ($)             f  x = f x
    runState (State f) s = f s
    

    这使得(=&lt;&lt;) = flip (&gt;&gt;=) 类似于(&lt;&lt;&lt;) = (.);它不是采用两个函数并返回第三个函数,而是采用一个函数(返回一个State)和一个State,并产生第二个State

    但是,我们将直接比较 (&gt;&gt;=)(&gt;&gt;&gt;) = flip (.),以便更好地对齐类型。 (同样,您可以将(.)(=&lt;&lt;) 进行比较。)

    -- f :: t -> a
    -- g ::      a -> b
    f >>> g =         \t -> let a       = ($)      f     t
                            in            ($)      g     a
    -- m :: State s a
    -- g ::         a -> State s b
    m >>= g = State $ \s -> let (a, s') = runState m     s
                            in            runState (g a) s'
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-16
      • 1970-01-01
      • 1970-01-01
      • 2016-03-31
      • 1970-01-01
      相关资源
      最近更新 更多