【问题标题】:Why do I use `let` and not just `val` to declare a variable inside a function in SML?为什么我使用 `let` 而不仅仅是 `val` 在 SML 中的函数内声明变量?
【发布时间】:2018-10-14 08:11:49
【问题描述】:

在 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?

【问题讨论】:

    标签: sml


    【解决方案1】:

    为什么不能在没有let 的函数内部使用val

    因为val是一种声明,let是一种表达式,函数体是一种表达式。

    let-表达式的句法结构是letdecinexpend。因此,在使用let-表达式作为函数体时,let 中的 exp 等效于函数体,但具有扩展的本地范围,无论 @ 987654339@ 补充道。

    let-表达式允许您使用任何类型的声明,而不仅仅是 val 声明。

    例如,您可以将异常处理用作用于回溯的控制流机制,并且您可以嵌套仅在本地使用并且可能需要多个参数来存储临时结果的辅助函数,但您可能不想公开异常或辅助函数。因此,对于Eight Queens puzzle,您可以改进this solution(来自关于函数式编程的补充说明,pp. 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 SMLnested local declarations in ML of NJ 的问答。

    【讨论】:

    • 所以val不能在函数体内使用,因为函数体必须是表达式?另一方面,使用val“outside”(即当我在脚本中写val x = 1)很好,因为“outside”允许声明? (这些东西听起来像是我不知道的函数式编程的基础知识!)
    • @Heisenberg:当“函数外”是指在函数声明之前或之后(例如在顶层,或在let-表达式的第一部分内,或其他地方的数量),那么是的,您可以在那里进行各种声明。这不是函数式编程的属性,而是标准 ML 语法的特定属性。在函数式编程的理论基础lambda calculus 中,只有 lambda 表达式,没有任何类型的声明。
    猜你喜欢
    • 2020-06-18
    • 2022-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-22
    • 2019-02-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多