haskell - Let vs. Haskell 中的 Lambda
问题描述
我正在阅读 Will Kurt 的“使用 Haskell 进行编程”。在关于词法作用域的第 3 课结束时,作者写道:
使用
let
表达式和 lambda 函数在本质上并不完全相同。例如,如果您尝试运行以下代码,则会导致错误:counter x = let x = x + 1 in let x = x + 1 in x
为了证明
let
和 lambda 不同,请完全按照此处的方式重写 counter 函数,但使用嵌套的 lambdas 而不是let
.
这是我的解决方案,它可以按我的预期工作:
counterLambda x = (\x -> (\x -> x) (x + 1)) (x + 1)
-- counterLambda 2 == 4
但是,正如作者建议的那样,如果我counter 2
在 ghci 中运行,它会永远挂起(使用 GHC 8.8.3)。
引擎盖下发生了什么?
PS:当我正确命名变量时它可以工作。
counter x = let a = x + 1 in let b = a + 1 in b
-- counter 2 == 4
解决方案
在 lambdas 和let
s 中,每个都x
遮盖了之前的那个。区别在于阴影的范围。lambda 参数的范围仅限于 lambda,但 let 绑定的范围是整个let ... = ... in ...
结构,因此根据自身let x = x + 1
定义,而根据unshadowed定义阴影。让我通过向 each 添加一个数字来演示每个实现的影子范围:x
(\x -> x) (x + 1)
x
x
x
counterLambda x0 = (\x1 -> (\x2 -> (\x3 -> x3) x2) (x1 + 1)) (x0 + 1)
counter x0 = let x1 = x1 + 1 in let x2 = x2 + 1 in x2
现在应该清楚为什么这些不同了。在 lambda 版本中,x1
is assigned x0 + 1
,而在let
版本中,x1
is assigned x1 + 1
,它不会终止。
推荐阅读
- azure-cosmosdb - 如何在 Azure Cosmos DB 中查询次要副本
- reactjs - 为 react-dropdown-tree-select.js 模块生成 .d.ts 文件
- jekyll - 图像的宏伟弹出式画廊不起作用
- java - 如何解决 Android Oreo Socket 连接问题
- java - 内部类无法访问从内部调用构造函数的方法初始化的外部类成员变量
- java - Android:在 webview 中加载特殊的 html 页面或 url 时转到下一个布局
- android - 无法解析 R.id.toolbar
- semantic-ui - 如何从菜单中删除底部边框
- r - R 软件绘图 3D 量子轨道(球面谐波)
- fortran - gfortran 混合了真实的类型