在SML中,我被教导了一种惯用的方法来定义函数的局部变量:
fun correct_fun() =
let val x = 1
in x + 2
end
为什么我必须使用let
,而不仅仅是val
:
fun incorrect_fun() =
val x = 1
x + 2
incorrect_fun()
抛出错误,但我不明白为什么。为什么不能在没有let
的函数内使用val?
答案 0 :(得分:2)
为什么
val
不能在没有let
的函数内使用?
因为val
是一种声明,let
是一种表达式,函数体是表达式。
let
- 表达式的句法结构为let
dec
in
exp
end
。因此,在使用let
- 表达式作为函数体时,exp
中的 let
等同于函数体,但具有扩展的局部范围 dec
添加的内容。
let
- 表达式允许您使用任何类型的声明,而不仅仅是val
声明。
例如,您可以将异常处理用作用于回溯的控制流机制,并且您可以嵌套仅在本地使用的辅助函数,并且可能需要多个参数来存储临时结果,但您可能不希望公开异常或辅助函数。因此对于Eight Queens puzzle,您可以改进this solution(来自关于函数式编程的补充说明,第140-143页,来自Niels Andersen):
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
- 表达式主要声明临时值时,您还可以考虑使用case-of
。有关Difference between "local" and "let" in SML和nested local declarations in ML of NJ的信息,请参阅问答。