Haskell 哈斯凯尔州单子通过的困惑

Haskell 哈斯凯尔州单子通过的困惑,haskell,monads,state-monad,Haskell,Monads,State Monad,在Haskell中,状态是monad,它被传递来提取和存储状态。在下面的两个示例中,都使用>传递状态monad,并且经过仔细验证(通过函数内联和归约)确认状态确实传递到下一步 但这似乎不是很直观。那么这是否意味着当我想通过状态单子时,我只需要>(或者>=和lambda表达式\s->a,其中s在a中不是免费的)?谁能在不费心减少功能的情况下对这一事实提供直观的解释 -- the first example tick :: State Int Int tick = get >>= \n

在Haskell中,状态是monad,它被传递来提取和存储状态。在下面的两个示例中,都使用
>
传递状态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
。这正是您想要表达的有状态计算。巧妙的一点是(将这种机器表示为单子的唯一目的是)不必费心传递状态。但要理解它是如何完成的,请参考
>=
on)的定义,暂时忽略它是一个转换器而不是最终的单子)

实际上相当于

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
tick=do
n(s,s)
在一个简化设置中,
(s->((),s))
,它在将不必要的参数删除到
put::s->s->((),s)
后是等效的,它使用一个值(第一个参数)替换当前状态,并生成一个有状态的操作,其结果是您删除的无意义的值
()
(因为您没有使用
>
而不是
>=
)。由于
put
的原因,基础状态已更改为
n+1
,因此它被传递

  • return
    对基础状态不做任何操作,它只返回其参数

  • 总之,
    tick
    以一些初始值
    s
    开始,它在内部将其更新为
    s+1
    ,并在侧面输出
    s


    另一个示例的工作方式完全相同,
    仅用于丢弃
    ()<代码> > 。但是状态一直都在传递。

    谢谢!读完它后,我意识到我只是不理解它被丢弃的价值,但是这个状态仍然是通过的。乐意帮助,如果答案是你满意的,请考虑接受它来结束这个问题。(这适用于stackoverflow上的所有问题),它有助于跟踪未解决的问题,并帮助其他人在提出自己的问题之前找到答案。也谢谢你的提示,哈哈
    tick :: State Int Int 
    tick = get >>= \n ->
        put (n+1) >>
        return n
    
    tick = do
        n <- get
        put (n + 1)
        return n