为什么我们的函数需要接受状态和输入,而不仅仅是包含输入的状态(或包含状态的输入?)。
我假设您可能希望应用具有相同状态的不同输入,因此您希望将它们分开保存,但这是唯一的原因吗?
我觉得我错过了一些基本的东西,但我无法掌握它。
为什么我们的函数需要接受状态和输入,而不仅仅是包含输入的状态(或包含状态的输入?)。
我假设您可能希望应用具有相同状态的不同输入,因此您希望将它们分开保存,但这是唯一的原因吗?
我觉得我错过了一些基本的东西,但我无法掌握它。
那是因为方便。一般来说,单独的参数,如果它们在概念上是分开的(我的意思是,它们不是单个对象的属性,例如),比打包在数据类型中要好,因为在前一种情况下,您可以使用柯里化、组合器和其他函数式方法的优点。
没有 monad,每个有状态的函数看起来像foo :: b -> s -> (s, a)
,而有了 monad,我们可以提取公共部分,将其命名为: newtype State s a = State (s -> (s, a))
,并为它定义return
和>>=
。此外,任何简单的函数bar :: a -> b
都可以通过简单的结果更改轻松转换为有状态的:bar :: a -> State s b
. 如果输入和状态都包含在单个参数中(例如,元组:foo :: (s, a) -> (s, a)
.
State monad 很有用,因为它强制执行从类型中显而易见的模式。
而不是让代码中的每个函数看起来像:
foo state x y = ... return (state', z)
你可以用State
它来明确你的意图是什么。
术语:如果您是 Haskell 的新手,很容易被“状态数据是可变的”之类的语句混淆/愚弄。来自命令式程序的人可能会认为“可变”意味着更改现有位置的值。对于 Haskell 的某些部分(例如IORef
),这确实是正确的。在State
单子的情况下,这是不正确的。
State
支持将状态突变为新状态 - 新状态完全独立于旧状态。没有任何东西在原地发生变异。
有时这被称为“有效的”编程——你得到了效果的好处,但没有使用“真正的”副作用——State
是完全纯粹的。