【问题标题】:destructuring tuple with let in ML在 ML 中使用 let 解构元组
【发布时间】:2021-04-07 01:14:49
【问题描述】:

在 sml 中,我可以在 let 中使用元组吗?如果是这样,语法是什么? 我可以要求这是同心模式匹配,但似乎应该有一个更少的样板方式。在下面的let 中,我想将v1v2 绑定到调用interpExp 返回的元组的两个值。然后我想用其中一个值调用interpExp 以获得另外两个值。

fun performOp (e1,op,e2,table) = 
    let val (v1,t1) = interpExp(e1,table)   (* interpExp returns 2-tuple, bind v1 and t2 to those two values *)
        and val (v2,t2) = interpExp(e1,t1)  (* use t1 which was bound on previous line *)
        and val v3 = (case op of
                           Plus => v1 + v2
                     | Minus => v1 - v2
                     | Times => v1 * v2
                     | Div => v1 / v2)
    in (v3,t2)
    end

在进一步的试验和错误中,似乎第二个和第三个val 是不必要的,此后v1v2 似乎不在下一个条款的范围内。

fun performOp (e1,op,e2,table) = 
    let val (v1,t1) = interpExp(e1,table) 
        and (v2,t2) = interpExp(e1,t1)  (* oops  t1, not in scope *)
        and v3 = (case op of
                           Plus => v1 + v2
                     | Minus => v1 - v2
                     | Times => v1 * v2
                     | Div => v1 / v2)
    in (v3,t2)
    end

在进一步的实验中,我发现了另一种语法,但我不确定有什么区别,即在let 中使用val 而不是and

fun performOp (e1,op,e2,table) = 
    let val (v1,t1) = interpExp(e1,table) 
        val (v2,t2) = interpExp(e1,t1)  (* oops  t1, not in scope *)
        val v3 = (case op of
                           Plus => v1 + v2
                     | Minus => v1 - v2
                     | Times => v1 * v2
                     | Div => v1 / v2)
    in (v3,t2)
    end

【问题讨论】:

    标签: pattern-matching sml ml


    【解决方案1】:

    一般来说,and 关键字在 SML 中用于引入多个相互递归的函数或数据类型。例如,我们可以将无端低效的奇偶校验定义为

    fun isEven 0 = true
      | isEven 1 = false
      | isEven n = isOdd (n - 1)
    
    and isOdd 0 = false
      | isOdd 0 = true
      | isOdd n = isEven (n - 1)
    

    还有一个数据类型的例子:

    datatype 'a exposed = Exposed of 'a * 'a stream
    and      'a stream  = Stream of unit -> 'a exposed
    

    但是,and 在其他一些上下文中也受支持(我认为是为了保持一致性?),其中它仅具有引入同时捆绑在一起的所有绑定的效果。例如,在

    val x = 7
    and y = 8
    

    xy 将同时引入。现在直接解决您的直接示例:

    1. 您呈现的第一个将遇到语法错误,因为它应该是and 而不是val and
    2. 您展示的第二个同时引入了所有这些绑定,因此您不能依赖第二个中的t1 --- 它尚未引入。
    3. 关于使用val,最后一个是正确的

    然而,所有这些都存在语法错误,因为op 也是一个保留字(它主要用于允许将中缀函数视为前缀函数,例如val sum = foldr op+ 0)。如果你改变它,就会给你留下类似的东西

    fun performOp (e1, binop, e2, table) = 
        let val (v1, t1) = interpExp (e1, table) 
            val (v2, t2) = interpExp (e1, t1)
            val v3 = (case binop of
                       Plus  => v1 + v2
                     | Minus => v1 - v2
                     | Times => v1 * v2
                     | Div   => v1 / v2)
        in (v3,t2)
        end
    

    那么它应该按预期工作。我还应该注意/ 用于reals 上的除法,所以如果你打算使用ints,它应该是div(也是中缀)。

    【讨论】:

    • 感谢您的解释。 op 是保留字是我没想到的;这对于初学者来说很难弄清楚。感谢您对/div 的评论。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-07-23
    • 2020-07-06
    • 1970-01-01
    • 2016-02-06
    • 1970-01-01
    • 1970-01-01
    • 2020-11-19
    相关资源
    最近更新 更多