在let
中使用相互依赖的绑定是否安全?例如:
let x = 1
y = x + 2
in y
它们是否可能并行评估?我的ghci
表明它被正确评估,但总是这样吗?
答案 0 :(得分:11)
Haskell是懒惰的评估。这意味着表达式仅根据需要进行评估。让我们从你的例子开始吧。
let x = 1
y = x + 2
in y
系统查看y
部分(表达式),并说"嘿。我知道y
等于什么。它等于x + 2
"但它只能评估x + 2
是否有x
的定义,因此它会做同样的事情并确定y
是1 + 2
当然是3
}。现在这只是懒惰评估的一小部分力量。下一个例子更全面地展示了它。
let x = 0 : y
y = 1 : x
in take 50 x
此表达式将正确评估,产生列表x
上的前50个元素,它们将0
和1
交替显示。 x
和y
这两个值都是相互依赖的无限列表,实际上在大多数语言中都会溢出堆栈。但是,评估规则允许系统仅查看所需的部分,在该示例中是前50个元素。
因此,为了回答有关评估顺序的问题,系统会评估它所看到的内容。如果该函数应该返回y
,它将评估y
,然后根据需要评估x
。如果您在第一个示例中添加了x
,则会评估x
并单独留下y
。例如,此代码不会出错。
let x = 1
y = error "I'm an error message!"
in x
这是因为永远不需要y
表单,因此甚至不会查看会导致程序崩溃的代码段。
答案 1 :(得分:2)
在Haskell中(无论您使用单个let
,多个let
,case
,where
还是函数参数),在评估时都会评估表达式另一个表达取决于它的价值。
因此,在您的情况下,只要y
的值是必需的(当然这取决于周围的程序),我们将评估y
并将x
评估为y
评价的一部分。
另一种思考方式是:无论何时使用变量的值,最迟都会在该点进行评估。也就是说它可能先前已被评估过(如果以前需要它),或者现在可以进行评估,但是,只要您使用该值,它就永远不会被评估。因此,除了性能原因之外,无需担心何时评估变量。