假设你想在Haskell中写一些有状态的函数.你必须使用这样的单项式。(使用任何状态单项式)
f :: x -> k -> (ST s) r
因此,这意味着函数基本上需要一些输入 x
和 k
可以使用和或修改世界来计算一个返回值。r
.
假设 x
是一个有状态的结构,可以通过 f
. 假设 k
是一个简单的键类型,例如用于访问在 x
. k
本身以后会被分配一个简单的数字类型,但我们不想现在就决定它的类型。
所以基本上我知道 x
是一个可变的东西,而 k
是不可改变的.问题是只看一下 f
的签名,我们无法判断,所以如果。f
发生在一些比较复杂的单体代码中,我们不能很好地推理这些变量。
举个例子。
g :: x -> k -> (ST s) r
g a i = do
...
f a i -- I don't know if i :: k depends on state
... --- I don't know if i was changed by f
我的意思是如果给我一个变量 i
无名氏 k
我不知道这是否取决于 s
的调用是否会影响其价值。f
.当然,这个问题在写纯函数时不存在,因为一切都不可变。
是否有一种方法可以方便地注释,更重要的是,静态地强制执行 k
当调用ST单体时,ST单体将保持不变。f
?
内部 ST
你可以肯定地告诉你什么是可变的:一个是 Int
始终是一个不可改变的整数,而一个 STRef s Int
是一个(不可变的)对可变的 Int
.
因此:
f :: STRef s Int -> String -> (ST s) Bool
可以(读取和)修改 Int
指向第一个参数,但只能读取作为第二个参数传递的不可更改的字符串。
在此之上。f
可能会创建(和变异)新的 STRef s
引用到新分配的值。它也可以修改其他值,如果 f
使用对这些值的引用来定义。例如,在
bar :: forall s . ST s ()
bar = do
x_ref <- newSTRef "hello"
let f :: STRef s String -> String -> ST s ()
f y_ref str = do
y <- readSTRef y_ref
writeSTRef x_ref y
writeSTRef y_ref (y ++ " change " ++ str)
...
呼叫 f
将会改变原来设置的字符串为 "hello"
和其引用被传递给 f
.
在你自己的例子中。
g :: x -> k -> (ST s) r
g a i = do
...
f a i -- I don't know if i :: k depends on state
... --- I don't know if i was changed by f
如果... i :: k
不是一个引用,它仍然有相同的值。如果它是一个引用,引用的值可能已经由 f a i
.