问题描述
在 sml 中,我可以在 let
中使用元组吗?如果是这样,语法是什么?
我可以要求将其作为同心模式匹配,但似乎应该有一个更少的样板方式。在下面的 let
中,我想将 v1
和 v2
绑定到调用 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
是不必要的,此后似乎 v1
和 v2
不在下一个子句的范围内。>
fun performOp (e1,table)
and (v2,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
在进一步的实验中,我发现了另一种语法,但我不确定有什么区别,即在 val
中使用 and
而不是 let
。>
fun performOp (e1,table)
val (v2,not in scope *)
val v3 = (case op of
Plus => v1 + v2
| Minus => v1 - v2
| Times => v1 * v2
| Div => v1 / v2)
in (v3,t2)
end
解决方法
一般来说,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
同时引入 x
和 y
。现在直接解决您的直接示例:
- 您提供的第一个会遇到语法错误,因为它应该是
and
而不是val and
- 您呈现的第二个同时引入了所有这些绑定,因此您不能在第二个中依赖
t1
---它尚未引入。 - 关于使用
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
然后它应该按预期工作。我还应该注意到 /
用于对 real
进行除法,因此如果您打算使用 int
代替,它应该是 div
(也是中缀) .