gpt4 book ai didi

haskell - Haskell 中的不可变变量是什么意思?

转载 作者:行者123 更新时间:2023-12-02 06:17:18 25 4
gpt4 key购买 nike

我对 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 不允许您修改现有变量。然而,它确实允许您重复使用变量名称,这就是这里发生的一切。查看此情况的一种方法是使用声明变量的 :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

这实际上是两个完全独立的不同变量,只是碰巧被称为相同的名称!如果您只要求 a,则较新的定义将是“首选”,但旧的定义仍然存在 - 正如 chi 在评论中所述,查看此内容的一种方法是使用 a 在函数中:

Prelude> let a = 2
Prelude> :i a
a :: Num a => a -- Defined at <interactive>:4:5
Prelude> let f x = a + x
Prelude> let a = 3
Prelude> f (-2)
0

f 永远不需要关心您是否定义了一个也称为 a 的新变量;从它的角度来看,a 是一个始终保持原样的不可变变量。

<小时/>

值得讨论一下为什么 GHCi 更喜欢后面的定义。否则,这在 Haskell 代码中不会发生;特别是如果您尝试编译以下模块,它只会给出有关重复定义的错误:

a = 1
a = 2

main :: IO ()
main = print a

GHCi 中允许这样的事情的原因是它的工作方式与 Haskell 模块不同。 GHCi 命令序列实际上形成了 IO monad 中的一系列操作;即该程序必须是

main :: IO ()
main = do
let a = 1
let a = 2
print a

现在,如果您了解了 monad,您就会知道这只是语法糖

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-block 中不允许的一些操作,特别是您可以定义 data 类型和 classes 。但任何正常的语句或变量定义都会像在 IO monad 中一样起作用。

关于haskell - Haskell 中的不可变变量是什么意思?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38040812/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com