我听说 Haskell 变量是不可变的,但我可以重新分配和更新变量值
I heard that Haskell variables are immutable but i am able to reassign and update variable values
我听说 Haskell 变量是不可变的,但我可以重新分配和更新变量值
你是在跟踪,而不是变异。
首先,请注意 GHCi 语法与 Haskell 源文件语法并不完全相同。特别是,x = 3
实际上曾经是非法的:
GHCi, version 7.10.2: http://www.haskell.org/ghc/ :? for help
Prelude> x = 3
<interactive>:2:3: parse error on input ‘=’
较新的版本通过简单地将任何此类表达式重写为 let x = 3
使这成为可能,这一直没问题:
GHCi, version 7.10.2: http://www.haskell.org/ghc/ :? for help
Prelude> let x = 3
Prelude> x
3
相比之下,在 Haskell 源文件中,let x = 3
本身从来都不合法。这仅适用于特定环境,即 monadic do
块.
main :: IO ()
main = do
let x = 3
print x
3
GHCi 提示符的设计实际上类似于 do
块中的行,所以让我们在下面讨论一下。注意我也可以写
main = do
let x = 1
let x = 3
print x
3
这基本上也是您的 GHCi 会话中发生的事情。然而,正如其他人所说,这是 不是 突变,而是 遮蔽 。要理解这是如何工作的,请注意上面本质上是一种 shorthand 的写法
main =
let x = 1
in let x = 3
in print x
因此,您有 两个嵌套范围。当您在某些表达式中查找变量时,Haskell 总是选择“最近的一个”,即在内部范围内:
main =
let x = 1
┌──
in│let x = 3
│in print x
└─
外部 x
根本没有被触及,它基本上与内部范围内发生的任何事情无关。如果询问您的文件中是否有可疑内容,编译器实际上会警告您:
$ ghc -Wall wtmpf-file16485.hs
[1 of 1] Compiling Main ( wtmpf-file16485.hs, wtmpf-file16485.o )
wtmpf-file16485.hs:3:8: warning: [-Wunused-local-binds]
<b>Defined but not used: ‘x’</b>
|
3 | let x = 1
| ^
wtmpf-file16485.hs:3:12: warning: [-Wtype-defaults]
• Defaulting the following constraint to type ‘Integer’
Num p0 arising from the literal ‘3’
• In the expression: 3
In an equation for ‘x’: x = 3
In the expression:
do let x = 1
let x = 3
print x
|
3 | let x = 1
| ^
wtmpf-file16485.hs:4:8: warning: [-Wname-shadowing]
<b>This binding for ‘x’ shadows the existing binding</b>
bound at wtmpf-file16485.hs:3:8
|
4 | let x = 3
| ^
那里:第二个定义简单地引入了一个new,更多的局部变量也恰好被称为x
,但与外部变量无关。 IE。我们不妨重命名它们:
main = do
let xOuter = 1
let xInner = 3
print xInner
所有这一切的结果是以这种方式“变异”的变量对使用原始变量的其他函数没有影响。示例:
GHCi, version 8.2.1: http://www.haskell.org/ghc/ :? for help
Loaded GHCi configuration from /home/sagemuej/.ghci
Loaded GHCi configuration from /home/sagemuej/.ghc/ghci.conf
Prelude> let x = 1
Prelude> let info = putStrLn ("x is ="++show x++" right now")
Prelude> x = 3
Prelude> info
x is =1 right now
另一个后果是尝试使用旧值的“更新”行为很有趣:
Prelude> let s = "World"
Prelude> s = "Hello"++s
Prelude> s
"HelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHell^C
这里,新绑定 而不是 只是将 "Hello"
添加到旧 s="World"
之前。相反,它将 "Hello"
添加到 它自己的结果值 之前,而结果值 又由 "Hello"
定义为...等等,递归地进行。
我听说 Haskell 变量是不可变的,但我可以重新分配和更新变量值
你是在跟踪,而不是变异。
首先,请注意 GHCi 语法与 Haskell 源文件语法并不完全相同。特别是,x = 3
实际上曾经是非法的:
GHCi, version 7.10.2: http://www.haskell.org/ghc/ :? for help
Prelude> x = 3
<interactive>:2:3: parse error on input ‘=’
较新的版本通过简单地将任何此类表达式重写为 let x = 3
使这成为可能,这一直没问题:
GHCi, version 7.10.2: http://www.haskell.org/ghc/ :? for help
Prelude> let x = 3
Prelude> x
3
相比之下,在 Haskell 源文件中,let x = 3
本身从来都不合法。这仅适用于特定环境,即 monadic do
块.
main :: IO ()
main = do
let x = 3
print x
3
GHCi 提示符的设计实际上类似于 do
块中的行,所以让我们在下面讨论一下。注意我也可以写
main = do
let x = 1
let x = 3
print x
3
这基本上也是您的 GHCi 会话中发生的事情。然而,正如其他人所说,这是 不是 突变,而是 遮蔽 。要理解这是如何工作的,请注意上面本质上是一种 shorthand 的写法
main =
let x = 1
in let x = 3
in print x
因此,您有 两个嵌套范围。当您在某些表达式中查找变量时,Haskell 总是选择“最近的一个”,即在内部范围内:
main =
let x = 1
┌──
in│let x = 3
│in print x
└─
外部 x
根本没有被触及,它基本上与内部范围内发生的任何事情无关。如果询问您的文件中是否有可疑内容,编译器实际上会警告您:
$ ghc -Wall wtmpf-file16485.hs
[1 of 1] Compiling Main ( wtmpf-file16485.hs, wtmpf-file16485.o )
wtmpf-file16485.hs:3:8: warning: [-Wunused-local-binds]
<b>Defined but not used: ‘x’</b>
|
3 | let x = 1
| ^
wtmpf-file16485.hs:3:12: warning: [-Wtype-defaults]
• Defaulting the following constraint to type ‘Integer’
Num p0 arising from the literal ‘3’
• In the expression: 3
In an equation for ‘x’: x = 3
In the expression:
do let x = 1
let x = 3
print x
|
3 | let x = 1
| ^
wtmpf-file16485.hs:4:8: warning: [-Wname-shadowing]
<b>This binding for ‘x’ shadows the existing binding</b>
bound at wtmpf-file16485.hs:3:8
|
4 | let x = 3
| ^
那里:第二个定义简单地引入了一个new,更多的局部变量也恰好被称为x
,但与外部变量无关。 IE。我们不妨重命名它们:
main = do
let xOuter = 1
let xInner = 3
print xInner
所有这一切的结果是以这种方式“变异”的变量对使用原始变量的其他函数没有影响。示例:
GHCi, version 8.2.1: http://www.haskell.org/ghc/ :? for help
Loaded GHCi configuration from /home/sagemuej/.ghci
Loaded GHCi configuration from /home/sagemuej/.ghc/ghci.conf
Prelude> let x = 1
Prelude> let info = putStrLn ("x is ="++show x++" right now")
Prelude> x = 3
Prelude> info
x is =1 right now
另一个后果是尝试使用旧值的“更新”行为很有趣:
Prelude> let s = "World"
Prelude> s = "Hello"++s
Prelude> s
"HelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHell^C
这里,新绑定 而不是 只是将 "Hello"
添加到旧 s="World"
之前。相反,它将 "Hello"
添加到 它自己的结果值 之前,而结果值 又由 "Hello"
定义为...等等,递归地进行。