我从概念上理解所有这些是什么,我只是希望有一些代码示例来说明如何在ML和Haskell中实现它们。
答案 0 :(得分:2)
Haskell变量(顶级定义,模式中的变量等)都是静态范围的。例如,程序:
aws s3 cp
将打印“全球价值”。即使在y = "global value"
f = print y
g = let y = "local value" in f
main = g
的定义中,函数g
在“重新定义”f
之后使用,此重新定义也不会影响使用静态的y
的定义(AKA词法)范围内定义f
的{{1}}定义了y
。
如果您想“实施”动态范围,您必须更具体地了解您的真实含义。如果您想知道是否可以在普通的Haskell中编写函数,例如:
f
这样addY :: Int -> Int
addY x = x + y
可能会引用从一个调用到下一个调用的不同变量,那么答案就是否定。在此定义中,y
始终引用相同的变量(在Haskell中,表示相同的不可变值),该变量可以通过程序的静态分析来确定,并且不能动态重新定义。
[[编辑:正如@Jon Purdy指出的那样,有一个Haskell扩展支持一种动态范围,以便下面打印具有相同功能的各种动态范围的本地值。
y
- 编辑结束 - ]]
对于延迟评估,有许多示例,例如以下内容进入交互式GHCi会话:
{-# LANGUAGE ImplicitParams #-}
f :: (?y :: String) => IO ()
f = print ?y
g = let ?y = "g's local value" in f
h = let ?y = "h's local value" in f
main = do
g -- prints g's local value
h -- prints h's local value
let ?y = "main's local value" in f -- prints main's value
在第一行中,如果评估是严格的,那么尝试完全评估无限列表take 3 [1,2..] -- gives [1,2,3]
let x = (15^2, 6 `div` 0)
fst x -- gives 225
let y = snd x
y -- *** Exception: divide by zero
(也可以写成[1,2..]
- 只计算1,2,3,...永远)将进入一个无限循环,永远不会调用[1..]
函数。在第二个示例中,如果评估是严格的,那么在定义take
时会发生除零错误,而不仅仅是在我们尝试打印其第二个组件之后。