作者热门文章
- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
在Haskell中,州通过monad来提取和存储州。在以下两个示例中,都使用>>
通过了State monad,并且进行了仔细的验证(通过函数内联和归约),确认该状态确实已传递到下一步。
但这似乎不是很直观。那么这是否意味着当我想通过State monad时,我只需要>>
(或>>=
和lambda表达式\s -> a
,其中s
在a
中不是免费的)?任何人都可以为这个事实提供直观的解释,而不必费心去减少功能吗?
-- the first example
tick :: State Int Int
tick = get >>= \n ->
put (n+1) >>
return n
-- the second example
type GameValue = Int
type GameState = (Bool, Int)
playGame' :: String -> State GameState GameValue
playGame' [] = get >>= \(on, score) -> return score
playGame' (x: xs) = get >>= \(on, score) ->
case x of
'a' | on -> put (on, score+1)
'b' | on -> put (on, score-1)
'c' -> put (not on, score)
_ -> put (on, score)
>> playGame xs
最佳答案
真正归结为了解状态与s -> (a, s)
同构。因此,在单声道操作中“包装”的任何值都是对某个状态s
(产生a
的有状态计算)进行转换的结果。
在两个有状态计算之间传递状态
f :: a -> State s b
g :: b -> State s c
>=>
组成它们
f >=> g
>>=
\a -> f a >>= g
a -> State s c
s
,允许其访问某些
a
,并产生某些
c
。因此,允许整个转换依赖于
a
,并且允许值
c
依赖于某些状态
s
。这正是您要表达状态计算的内容。整洁的东西(将这种机器表示为monad的唯一目的)是您不必费心传递状态。但是要了解它是如何完成的,请参考
hackage上
>>=
的定义),暂时忽略一下它是一个转换器而不是最终的monad。
m >>= k = StateT $ \ s -> do
~(a, s') <- runStateT m s
runStateT (k a) s'
StateT
和
runStateT
的包装和展开,此处
m
的格式为
s -> (a, s)
,
k
的格式为
a -> (s -> (b, s))
,并且希望生成有状态的转换
s -> (b, s)
。因此结果将是
s
的函数,要生成
b
,可以使用
k
,但首先需要
a
,如何生成
a
?您可以采用
m
并将其应用于状态
s
,从第一个单子动作
s'
中获得修改后的状态
m
,然后将该状态传递给
(k a)
(类型为
s -> (b, s)
)。在这里,状态
s
已通过
m
成为
s'
,并传递给
k
成为某些最终的
s''
。
State
-actions的小步骤来构建计算,然后让
do
-notation或bind(
>>=
)进行链接/传递。
>>=
和
>>
之间的唯一区别是您关心或不关心非状态结果。
a >> b
a >>= \_ -> b
a
输出的,您都将其丢弃(仅保留修改后的状态),并与其他操作
b
继续(传递状态)。
tick :: State Int Int
tick = get >>= \n ->
put (n+1) >>
return n
do
表示法将其重写为
tick = do
n <- get
put (n + 1)
return n
get
当前状态并将其公开(在简化设置中为
get :: s -> (s, s)
),
<-
表示您确实关心该值,并且不想将其丢弃,底层状态也传递给了背景保持不变(
get
的工作方式)。
put :: s -> (s -> ((), s))
(在将不必要的括号删除到
put :: s -> s -> ((), s)
之后等效)采用一个值将当前状态替换为(第一个参数),并产生有状态操作,其结果是您删除的无趣值
()
(因为您不使用
<-
或因为您使用
>>
而不是
>>=
)。由于
put
,基础状态已更改为
n + 1
,因此将其继续传递。
return
对基础状态不执行任何操作,它仅返回其参数。
tick
从某个初始值
s
开始,在内部将其更新为
s+1
并在侧面输出
s
。
>>
仅用于丢弃由
()
生成的
put
。但是状态总是无处不在。
关于haskell - 关于 State 单子(monad)在 haskell 逝世的困惑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42384473/
我是一名优秀的程序员,十分优秀!