在Haskell中,如何区分单项函数定义中的可突变引用与常规变量?

问题描述 投票:1回答:1

假设你想在Haskell中写一些有状态的函数.你必须使用这样的单项式。(使用任何状态单项式)

f :: x -> k -> (ST s) r

因此,这意味着函数基本上需要一些输入 xk可以使用和或修改世界来计算一个返回值。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?

haskell immutability state-monad
1个回答
2
投票

内部 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.

© www.soinside.com 2019 - 2024. All rights reserved.