Haskell使用什么类型的范围?

时间:2008-12-02 06:05:54

标签: haskell scope alias

我正在试图弄清楚Haskell是使用动态还是静态作用域。 我意识到,例如,如果你定义:

let x = 10

然后定义函数

let square x = x*x

你有2个不同的“x”,这是否意味着它是动态范围的?如果没有,它使用什么范围,为什么?

此外,Haskell变量是否有别名(相同内存位置/值的不同名称)?

感谢。

9 个答案:

答案 0 :(得分:11)

Haskell(广泛地说)使用与大多数其他语言完全相同的词汇范围。

例如

x = 10

在全局范围内通过x引用的值,而

square x = x * x

将导致x被词法限定为函数平方。如果你认为上述形式是一种语法精确的话,它可能会有所帮助:

square = \ x -> x * x

关于你的另一个问题,我不确定你的别名是什么意思

答案 1 :(得分:6)

你的陈述中有些问题......

  • Haskell中没有可变变量只是定义(或不​​可变变量)
  • 可变内存位置是Haskell中不存在的概念

在你的例子中, x 而不是 10在函数中只是一个square的参数,可以取任何值(你可以在以后指定类型)案例10,但只是在这种情况下。

以下是Curt Sampson提供的别名示例:

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

答案 2 :(得分:6)

仅回答问题的第二部分:

对于相同的“内存位置”,您可以有多个别名,但由于它们都是不可变的,因此在大多数情况下无关紧要。

哑巴的例子:

foo x y = x * y
bar z = foo z z

当从foo调用bar时,xy显然都是相同的值。但由于您无法修改xy,因此您甚至都不会注意到。

答案 3 :(得分:3)

由于问题的第一部分已经被其他人回答,这是第二部分:

我假设aliasing你的意思是one name for another。由于haskell是一种函数式语言,并且函数在任何情况下都表现为普通标识符,因此您可以这样做:

y = x

将为函数y定义别名x。请注意,一切都是功能。即使它看起来像“变量”,它只是一个不带参数的无效函数。类型的别名如下所示:

type Function = Double -> Double

将为类型Function

定义别名Double -> Double

答案 4 :(得分:2)

在您的示例中,x的全局定义由x的本地定义遮蔽。在Haskell中,变量的作用域由源代码的静态读取决定 - 这称为词法作用域,但可以使用隐式参数获得类似于动态作用域的东西(但这可能导致一些意外行为(我读过;从不我自己试过))。

答案 5 :(得分:2)

Haskell使用静态嵌套作用域。与具有静态嵌套作用域的其他语言相比,有点令人困惑的是,名称的范围是包含其定义之前的测试的块。例如

evens = 0 : map (+1) odds
odds  = map : (+1) evens

这里''赔率'的名称在'evens'的定义范围内,尽管有一个令人惊讶的事实,即'赔率'尚未定义。 (该示例定义了偶数和奇数的两个无限列表。)

具有类似范围规则的死语言是Modula-3。但是Haskell有点棘手,因为你可以尝试在同一范围内“重新定义”一个变量,而只是引入另一个递归方程。对于首先学习ML或Scheme的人来说,这是一个陷阱:

let x = 2 * n
    x = x + 1   -- watch out!

这是非常好的ML或Scheme let *,但是Haskel有方案letrec语义,没有对lambda值的限制。难怪这是棘手的事情!

答案 6 :(得分:1)

简明扼要地总结其他答案:

  1. 词汇范围
  2. 别名就像x = 1; y = x一样简单,但通常不重要,因为事情是不可变的。
  3. 您在示例中使用的let语法看起来就像是在交互式ghci>提示符下。交互模式下的所有内容都发生在IO monad中,因此事情看起来可能比正常情况更容易变化。

答案 7 :(得分:0)

好吧,正如我认为人们已经说过的那样,Haskell没有大多数其他语言中的变量,它只有表达式。在您的示例中let x = 10 x是一个总是求值为10的表达式。虽然您可以使用作用域规则通过将x定义为另一个表达式来隐藏它,但您实际上无法在以后更改x的值。 / p>

答案 8 :(得分:0)

是的,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