sml - 为什么我使用 `let` 而不仅仅是 `val` 在 SML 中的函数内声明变量?
问题描述
在 SML 中,我学会了将函数局部变量定义为的惯用方法:
fun correct_fun() =
let val x = 1
in x + 2
end
为什么我必须使用let
,而不是val
像这样:
fun incorrect_fun() =
val x = 1
x + 2
抛出一个错误,incorrect_fun()
但我不明白为什么。为什么 val 不能在没有 的函数内使用let
?
解决方案
为什么不能在没有
val
的函数内部使用let
?
因为val
是一种声明,let
是一种表达式,而函数体是一种表达式。
- 表达式的句法结构let
是. 因此,在使用 -表达式作为函数体时, in相当于函数体,但具有扩展的本地范围,无论添加什么。let
dec
in
exp
end
let
exp
let
dec
-let
表达式允许您使用任何类型的声明,而不仅仅是val
声明。
例如,您可以将异常处理用作用于回溯的控制流机制,并且您可以嵌套仅在本地使用并且可能需要多个参数来存储临时结果的辅助函数,但您可能不想公开异常或辅助功能。因此,对于八皇后谜题,您可以改进此解决方案(来自Niels Andersen的函数式编程补充说明,第 140-143 页):
fun concatMap f xs = String.concat (List.map f xs)
fun concatTab f n = String.concat (List.tabulate (n, f))
fun dots n = concatTab (fn _ => ". ") n
fun show ys = concatMap (fn y => dots (y - 1) ^ "* " ^ dots (8 - y) ^ "\n") ys
fun queen dims =
let exception Queen
fun beats ((x,y),(x1,y1)) = (* x = x1 *)
(* orelse *) y = y1
orelse x + y = x1 + y1
orelse x - y = x1 - y1
fun safe ((x, y), _, []) = true
| safe ((x, y), x1, y1::ys) =
not (beats ((x, y), (x1, y1))) andalso safe ((x, y), x1 + 1, ys)
fun queen' ((0, _), ys) = ys
| queen' ((_, 0), _) = raise Queen
| queen' ((x, y), ys) =
if safe ((x, y), x + 1, ys)
then queen' ((x - 1, 8), y :: ys)
handle Queen => queen' ((x, y - 1), ys)
else queen' ((x, y - 1), ys)
in queen' (dims, []) end
展示它;
- print (show (queen ((8,8))));
. . . . * . . .
. . . . . . * .
. * . . . . . .
. . . . . * . .
. . * . . . . .
* . . . . . . .
. . . * . . . .
. . . . . . . *
当您使用let
-expressions 主要声明临时值时,您还可以考虑使用case-of
. 有关SML 中“local”和“let”之间的区别以及NJ ML 中的嵌套本地声明,请参阅问答。
推荐阅读
- gcc - Linux Mint 19.1 XFCE下无法编译TPLINK TL-WN822N驱动
- python - 将 url 拆分为目录并转换为 json 树
- react-native - 如何在 ReactNative 中解析 JSON 数据?
- ios - 滚动时UITableView多节冲突
- c# - 如何取消订阅此 lambda 事件?
- node.js - 如何刷新当前页面并避免重定向到登录页面
- pcre - 有条件地替换字符
- powershell - 组合来自不同实例的两个 SQL 查询的结果,不可链接
- javascript - Angular 6 - 日期管道
- c++ - 如果值等于键,则合并映射中的条目