在 Haskell 中通过引用传递?
Pass by Reference in Haskell?
来自 C# 背景,我会说 ref
关键字在某些情况下非常有用,在这些情况下,需要更改方法参数以直接影响设置参数的值类型的传递值至 null
。
此外,out
关键字在返回大量逻辑上不相关的值时可以派上用场。
我的问题是:在Haskell中是否可以通过引用将参数传递给函数?如果不是,直接替代方案是什么(如果有)?
My question is: is it possible to pass a parameter to a function by reference in Haskell? If not, what is the direct alternative (if any)?
不,Haskell 中的值是不可变的(好吧,do
表示法会产生一些可变性的错觉,但这一切都发生在函数内部,是一个完全不同的话题)。如果要更改值,则必须 return 更改后的值并让调用者处理它。例如,查看随机数生成函数 next
return 的值 和 更新的 RNG。
Also, the out keyword can come in handy when returning a multitude of various logically unconnected values.
因此,您也不能 out
。如果你想 return 几个完全断开连接的值(此时你可能应该考虑为什么断开连接的值是从单个函数 return 编辑的),return 一个元组。
这取决于上下文。没有任何上下文,不,你不能(至少不是你的意思)。有了上下文,如果你愿意,你很可能能够做到这一点。特别是,如果你在 IO
或 ST
中工作,你可以分别使用 IORef
或 STRef
,以及可变数组、向量、哈希表、弱哈希表(我相信只有IO
)等。一个函数可以采用其中的一个或多个并产生一个动作,该动作(在执行时)将修改这些引用的内容。
另一种上下文,StateT
,给人一种纯粹实现的可变 "state" 值的错觉。您可以使用复合状态并将 lenses 传递给它,为某些目的模拟引用。
在 Haskell 和 ML 等语言中,"pass-by-value" 和 "pass-by-reference" 之间没有区别,因为在这些语言中无法为变量赋值。首先不可能让 "changes to a method parameter" 影响任何传递的变量。
不,这是不可能的,因为 Haskell 变量是不可变的,因此,Haskell 的创建者一定认为没有必要传递无法更改的引用。
考虑一个 Haskell 变量:
let x = 37
为了改变这个,我们需要制作一个临时变量,然后将第一个变量设置为临时变量(修改)。
let tripleX = x * 3
let x = tripleX
如果Haskell通过引用传递,我们可以这样做吗?
答案是否。
假设我们试过:
tripleVar :: Int -> IO()
tripleVar var = do
let times_3 = var * 3
let var = times_3
这段代码的问题是最后一行;虽然我们可以想象变量是通过引用传递的,但新变量不是。
换句话说,我们引入了一个新的 local 同名变量;
再看最后一行:
let var = times_3
Haskell不知道我们要"change"一个全局变量;因为我们不能重新分配它,所以我们在本地范围内创建一个具有相同名称的新变量,因此不会更改引用。 :-(
tripleVar :: Int -> IO()
tripleVar var = do
let tripleVar = var
let var = tripleVar * 3
return()
main = do
let x = 4
tripleVar x
print x -- 4 :(
来自 C# 背景,我会说 ref
关键字在某些情况下非常有用,在这些情况下,需要更改方法参数以直接影响设置参数的值类型的传递值至 null
。
此外,out
关键字在返回大量逻辑上不相关的值时可以派上用场。
我的问题是:在Haskell中是否可以通过引用将参数传递给函数?如果不是,直接替代方案是什么(如果有)?
My question is: is it possible to pass a parameter to a function by reference in Haskell? If not, what is the direct alternative (if any)?
不,Haskell 中的值是不可变的(好吧,do
表示法会产生一些可变性的错觉,但这一切都发生在函数内部,是一个完全不同的话题)。如果要更改值,则必须 return 更改后的值并让调用者处理它。例如,查看随机数生成函数 next
return 的值 和 更新的 RNG。
Also, the out keyword can come in handy when returning a multitude of various logically unconnected values.
因此,您也不能 out
。如果你想 return 几个完全断开连接的值(此时你可能应该考虑为什么断开连接的值是从单个函数 return 编辑的),return 一个元组。
这取决于上下文。没有任何上下文,不,你不能(至少不是你的意思)。有了上下文,如果你愿意,你很可能能够做到这一点。特别是,如果你在 IO
或 ST
中工作,你可以分别使用 IORef
或 STRef
,以及可变数组、向量、哈希表、弱哈希表(我相信只有IO
)等。一个函数可以采用其中的一个或多个并产生一个动作,该动作(在执行时)将修改这些引用的内容。
另一种上下文,StateT
,给人一种纯粹实现的可变 "state" 值的错觉。您可以使用复合状态并将 lenses 传递给它,为某些目的模拟引用。
在 Haskell 和 ML 等语言中,"pass-by-value" 和 "pass-by-reference" 之间没有区别,因为在这些语言中无法为变量赋值。首先不可能让 "changes to a method parameter" 影响任何传递的变量。
不,这是不可能的,因为 Haskell 变量是不可变的,因此,Haskell 的创建者一定认为没有必要传递无法更改的引用。
考虑一个 Haskell 变量:
let x = 37
为了改变这个,我们需要制作一个临时变量,然后将第一个变量设置为临时变量(修改)。
let tripleX = x * 3
let x = tripleX
如果Haskell通过引用传递,我们可以这样做吗?
答案是否。
假设我们试过:
tripleVar :: Int -> IO()
tripleVar var = do
let times_3 = var * 3
let var = times_3
这段代码的问题是最后一行;虽然我们可以想象变量是通过引用传递的,但新变量不是。
换句话说,我们引入了一个新的 local 同名变量;
再看最后一行:
let var = times_3
Haskell不知道我们要"change"一个全局变量;因为我们不能重新分配它,所以我们在本地范围内创建一个具有相同名称的新变量,因此不会更改引用。 :-(
tripleVar :: Int -> IO()
tripleVar var = do
let tripleVar = var
let var = tripleVar * 3
return()
main = do
let x = 4
tripleVar x
print x -- 4 :(