在下面的代码中,我得到了预期的结果:
Prelude Control.Monad.State> runState ( put 10 >> return 5 ) 9
(5,10)
但令我感到困惑的是put
给return
的价值有多精确到最终结果,或者后来隐藏和取出的价值究竟是多少。我已经在Haskell中找到了许多有关状态的教程,但是我还没有找到一个真正的解释,真正以一种不高水平的方式将其分解。
我对>>
的理解是左边的值会被删除,所以这增加了我对put
的值如何传递的困惑。
提前感谢您帮助理解这一点。
答案 0 :(得分:5)
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" />
<h2 class="title text-center">my<span class="highlight">Logo</span></h2>
最终只是函数State s a
的包装器
因此,出于学习的目的,可能更容易考虑这一点
直接起作用,没有额外的包装。我们还可以定义类型同义词
这可以使它更容易阅读。我将显示没有的类型sigatures
首先,然后是它。
我们有monad定义(使用重命名的函数):
s -> (a, s)
我们还可以定义特定于州的功能:
sReturn :: a -> (s -> (a, s))
sReturn x = \s -> (x, s)
(+>>=) :: (s -> (a, s)) -> (a -> (s -> (b, s))) -> (s -> (b, s))
f +>>= g = \s1 ->
let (a, s2) = f s1
(b, s3) = (g a) s2
in (b, s3)
(+>>) :: (s -> (a, s)) -> (s -> (b, s)) -> (s -> (b, s))
f +>> g = f +>>= (\_ -> g)
注意,我已经包含了一些额外的括号和一些技术上的东西 不必要的,但希望澄清事情。
您看到putS :: s -> (s -> ((), s))
putS newState = \s -> ((), newState)
getS :: s -> (s, s)
getS = \s -> (s, s)
runS :: (s -> (a, s)) -> s -> (a, s)
runS f s = f s
之类的任何地方,都可以替换它
上面代码中的(s -> (a, s))
,使用此类型的同义词:
State s a
进行替换,我们获得了签名:
type State s a = s -> (a, s)
现在,如果我们翻译您的示例,我们可以按照缩减的步骤进行操作:
sReturn :: a -> State s a
(+>>=) :: State s a -> (a -> State s b) -> State s b
(+>>) :: State s a -> State s b -> State s b
putS :: s -> State s ()
getS :: State s s
runS :: State s a -> s -> (a, s)
我强烈建议在尝试学习像runS ( putS 10 +>> sReturn 5 ) 9 -- The initial expression
runS ( putS 10 +>>= (\_ -> sReturn 5) ) 9 -- Apply (+>>)
runS ( \s1 -> -- Apply (+>>=)
let (a, s2) = (putS 10) s1
(b, s3) = ((\_ -> sReturn 5) a) s2
in (b, s3) )
9
runS ( \s1 ->
let (a, s2) = (putS 10) s1
(b, s3) = (sReturn 5) s2 -- Reduce lambda application
in (b, s3) )
9
runS ( \s1 ->
let (a, s2) = (\s -> ((), 10)) s1 -- Apply putS
(b, s3) = (sReturn 5) s2
in (b, s3) )
9
runS ( \s1 ->
let (a, s2) = ((), 10) -- Reduce lambda application
(b, s3) = (sReturn 5) s2
in (b, s3) )
9
runS ( \s1 ->
let (b, s3) = (sReturn 5) 10 -- Substitute for s2 (a is not needed)
in (b, s3) )
9
runS ( \s1 ->
let (b, s3) = (\s -> (5, s)) 10 -- Apply sReturn
in (b, s3) )
9
runS ( \s1 ->
let (b, s3) = (5, 10) -- Reduce lambda application
in (b, s3) )
9
runS ( \s1 -> (5, 10) ) 9 -- Substitute for (b, s3)
(\s1 -> (5, 10)) 9 -- Apply runS
(5, 10) -- Reduce lambda application
这样的新Haskell抽象时尝试逐步减少这种方法。这似乎是每次都要经历的很多步骤,但是,当你工作时
随着抽象的增加,你会发展出一种易于理解的直觉
无需写出步骤。
State的直觉部分是有状态或状态依赖的值是从状态值到包含状态相关值和新状态值的对的函数。这允许它接受新状态并适当地改变其值并返回新的修改状态。 State
monad方法自动处理这些状态值的线程。
此外,真正的State
只是我们上面使用的函数类型的包装器。因此,我们在这里所做的与它的实际方式之间的唯一区别是实际上&#34;完成后我们只是省略了State
内的函数值的换行和解包。
答案 1 :(得分:2)
状态monad模拟隐式可变状态/变量。 var myApp = new Framework7({
material: true //enable Material theme
})
在变量中写入10并返回虚拟值put 10
。然后()
会丢弃... >> return 5
并返回()
。
您可以从其类型中找到它:
5
因此,整个monadic计算put :: s -> State s ()
-- ^ -- the type of the returned value
将内部变量修改为10,但返回5.
最后,put 10 >> return 5
提供runState (...) 9
作为隐式变量的初始值(将立即被覆盖),运行计算,然后
提取变量和返回值,用这些构建一对。
答案 2 :(得分:2)
考虑它的方法是runState (put 10 >> return 5) 9
首先获取9
并将其保存在状态变量中。然后它开始执行monadic计算。
put 10
用9
替换状态(当前为10
)。然后return 5
导致monadic计算的输出为5
。
runState
将monadic计算和初始状态值作为参数。然后它运行monadic计算,然后返回计算结果和状态变量的最终值。