题
我试图弄清楚 Haskell 是否使用动态或静态作用域。我意识到,例如,如果您定义:
let x = 10
然后定义函数
let square x = x*x
您有 2 个不同的“x”,这是否意味着它是动态作用域的?如果不是,它使用什么范围,为什么?
另外,Haskell 变量可以有别名(同一内存位置/值的不同名称)吗?
谢谢。
解决方案
你的说法有一些错误...
- Haskell 中没有可变变量,只有定义(或不可变变量)
- 变量内存位置是 Haskell 中不存在的概念
在你的例子中, X 是 不是 函数中的 10 只是 square 的一个参数,可以采用任何值(您可以稍后指定类型),在本例中为 10 但仅在本例中。
这是由提供的别名示例 科特·桑普森:
import Data.IORef
main :: IO ()
main = do x <- newIORef 0 -- write 0 into x
readIORef x >>= print -- x contains 0
let y = x
readIORef y >>= print -- y contains 0
writeIORef x 42 -- write 42 into x
readIORef y >>= print -- y contains 42
其他提示
Haskell中使用(广义地说)完全相同的词法作用域如大多数其他语言。
例如
x = 10
在通过x
在全球范围内引用的值,而
square x = x * x
将导致x
被词法作用域的功能方块。它可以帮助,如果你认为上面的表格是一个语法精密的:
square = \ x -> x * x
至于你的其他问题,我不知道你的别名是什么意思
应答仅问题的第二部分:
您可以有相同的“记忆区”几个别名,但由于它们都是不可变的,不要紧的大部分时间。
哑示例:
foo x y = x * y
bar z = foo z z
当foo
从bar
称为内,既x
和y
显然是相同的值。但是,因为你不能修改任何x
或y
,你甚至不会注意到。
作为问题的第一部分已经被他人回答,这里是第二部分:
我的aliasing
假设你的意思one name for another
。作为Haskell是一个功能的语言,和功能在任何情况下表现为正常的标识符,可以是这样做的:
y = x
这将定义一个别名y
为函数x
。需要注意的是一切的功能。即使它看起来像一个的“变量” 的,它只是一个无参函数不带参数。对于类型别名看起来像这样:
type Function = Double -> Double
这将定义一个别名Function
为类型Double -> Double
Haskell使用静态嵌套的作用域。什么是有点混乱与具有静态嵌套作用域其他语言相比是一个名字的范围是嵌段,它包括在其定义前述测试即可。例如
evens = 0 : map (+1) odds
odds = map : (+1) evens
在这里命名为“赔率”是在范围上的“找齐”的定义,尽管“赔率”尚未定义的令人惊讶的事实。 (此示例定义偶数和奇数两个无限列表。)
具有类似范围规则甲死语言是MODULA-3。但是哈斯克尔是,你可以尝试“重新定义”同一范围内的一个变量,而是你刚才介绍另一个递推公式有点棘手。这是人的陷阱谁学会ML或Scheme第一:
let x = 2 * n
x = x + 1 -- watch out!
这是非常好的ML或Scheme让*,但哈斯克尔具有letrec语义方案,而不限制于λ值。难怪这是棘手的问题!
在你的例子中,x的全局定义由x的本地定义的阴影。在Haskell中,一个变量的作用域是由源代码的静态读数确定 - 这就是所谓的词汇范围,但可以得到类似于隐含参数动态作用域的东西(但可能会导致一些意外的行为(我读过,从来没有试图“时间自己))。
简单总结一下其他答案:
- 词汇范围
- 别名就像这样简单
x = 1; y = x
但通常并不重要,因为事情是不可变的。
这 let
您在示例中使用的语法看起来像是交互式的 ghci>
迅速的。交互模式下的所有内容都发生在 IO monad 内,因此那里的事物可能比正常情况下显得更加可变。
好了,因为我觉得人们已经说过,Haskell没有任何变量,在其他语言中,它只有表达式。在您的例子let x = 10
x是始终计算为10的表达你不能真正改变x的值以后,虽然你可以使用范围规则定义X是另一种表达方式将其隐藏。
是,Haskell有别名。试试这个小程序:
import Data.IORef
main :: IO ()
main = do x <- newIORef 0 -- write 0 into x
readIORef x >>= print -- x contains 0
let y = x
readIORef y >>= print -- y contains 0
writeIORef x 42 -- write 42 into x
readIORef y >>= print -- y contains 42