如何在ml和haskell中实现静态范围,动态范围和延迟评估?

时间:2016-11-27 18:32:31

标签: haskell scope ml

我从概念上理解所有这些是什么,我只是希望有一些代码示例来说明如何在ML和Haskell中实现它们。

1 个答案:

答案 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时会发生除零错误,而不仅仅是在我们尝试打印其第二个组件之后。