Haskell中的不可变变量是什么意思?
我对Haskell中不可变变量的概念感到非常困惑。似乎我们无法更改Haskell中变量的值。但当我在GHCI中尝试以下代码时,变量的值似乎发生了变化:Haskell中的不可变变量是什么意思?,haskell,functional-programming,immutability,ghci,Haskell,Functional Programming,Immutability,Ghci,我对Haskell中不可变变量的概念感到非常困惑。似乎我们无法更改Haskell中变量的值。但当我在GHCI中尝试以下代码时,变量的值似乎发生了变化: Prelude> foo x=x+1 Prelude> a=1 Prelude> a 1 Prelude> foo a 2 Prelude> a=2 Prelude> a 2 Prelude> foo a 3 这是否与不可变变量的概念相冲突 非常感谢 Haskell不允许修改现有变量。然而,它确实允许您
Prelude> foo x=x+1
Prelude> a=1
Prelude> a
1
Prelude> foo a
2
Prelude> a=2
Prelude> a
2
Prelude> foo a
3
这是否与不可变变量的概念相冲突
非常感谢 Haskell不允许修改现有变量。然而,它确实允许您重用变量名,这就是这里所发生的一切。一种方法是使用
:i[nfo]
指令询问GHCi,其中变量声明为:
Prelude> let a = 1
Prelude> :i a
a :: Num a => a -- Defined at <interactive>:2:5
Prelude> let a = 2
Prelude> :i a
a :: Num a => a -- Defined at <interactive>:4:5
f
无需关心您是否定义了一个新变量,该变量也称为a
;从它的角度来看,a
是一个始终保持不变的变量
值得一提的是,为什么GHCi更喜欢后面的定义。这在Haskell代码中不会发生,否则会发生;特别是,如果您试图编译以下模块,它只会给出一个关于重复定义的错误:
a = 1
a = 2
main :: IO ()
main = print a
GHCi中允许这样做的原因是它与Haskell模块的工作方式不同。GHCi命令序列实际上形成了IO monad†中的一系列动作;i、 e.该计划必须
main :: IO ()
main = do
let a = 1
let a = 2
print a
现在,如果你已经了解了单子,你就会知道这只是语法糖
main =
let a = 1 in (let a = 2 in (print a))
这就是为什么可以重复使用名称a
:第二个名称a=2
,比第一个名称的范围更窄。因此,它更具有地方性,而地方定义具有优先权。这是不是一个好主意有点争议;一个很好的理由是你可以有一个
greet :: String -> IO ()
greet name = putStrLn $ "Hello, "++name++"!"
它不会因为有人在别处定义了它而停止工作
name :: Car -> String
name car | rollsOverAtRightTurn car = "Reliant Robin"
| fuelConsumption car > 50*litrePer100km
= "Hummer"
| ... = ...
此外,在GHCi中游手好闲时可以“重新定义”变量是非常有用的,尽管在适当的程序中重新定义内容并不是一个好主意,因为它应该显示一致的行为
†正如dfeuer所言,这并非全部事实。您可以在GHCi中执行
IO
do块中不允许的某些操作,特别是您可以定义数据
类型和类
es。但是任何正常的语句或变量定义都与IO
monad中的一样。(使用GHCi的另一个答案很好,但澄清一下,它并不特定于GHCi或monad…)
正如您可以从以下Haskell程序
main =
let x = 1 in
let f y = x + y in
let x = 2 in
print (x * f 3)
打印8
而不是10
,变量只能在Haskell中“绑定”,不能“变异”。换句话说,上面的程序相当于(称为α-等效,仅表示绑定变量名称的一致更改;有关更多详细信息,请参阅)
显然
x1
和x2
是不同的变量。这在我的rple中不起作用…试着把a=1;a=2
在.hs
文件中,并使用ghc
编译它。GHCi命令是IO操作,因此就像键入的所有内容都在do
块中一样。这意味着对相同名称的后续赋值就像嵌套的让s对旧绑定进行阴影处理。明白了!非常感谢。这让我非常困惑。另外:尝试GHCi(即使在单独的行中)let a=4;设fx=x+a;设a=0;f 2
并查看6
作为答案,确认旧a
的值确实没有更改。缺少一点:GHCi允许数据
,新类型
,类型
,类
和实例
声明,Haskelldo
语法中不允许使用。鉴于GHCi是一个交互式环境,它是一个基本功能。有多少次定义输入错误?如果每次这样做时都必须选择一个全新的名称,那么很容易就会出现无法读取的名称,如myFunction7
,其中以前所有myFunction
的定义都包含错误,并且在使用正确的定义时必须记住始终添加该7
,对。如果这是必需的,那么我们就需要调整一个完全不同的工作流,可能是有明确范围的。我认为,GHCi的顶层实际上更像ML而不是Haskell。
main =
let x = 1 in
let f y = x + y in
let x = 2 in
print (x * f 3)
main =
let x1 = 1 in
let f y = x1 + y in
let x2 = 2 in
print (x2 + f 3)