In sml can I use a tuple in a let
? If so what would the syntax be?
I can require this as concentric pattern matches, but it seems there should be a less boilerplate way. In the let
below, I'd like to bind v1
and v2
to the two values of the tuple returned from calling interpExp
. Then I'd like to call interpExp
with one of those values to get two more values.
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
On further trial and error, it seems the second and third val
are unnecessary, and thereafter it seems the v1
and v2
are not in scope for the next clause.
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
On further experimentation I've discovered yet another syntax, but I'm not sure what the difference is, i.e., using val
rather than and
in the let
.
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
Generally speaking, the and
keyword is used in SML for introducing multiple mutually recursive functions or datatypes. For example, we could define gratuitously inefficient parity checking as
fun isEven 0 = true
| isEven 1 = false
| isEven n = isOdd (n - 1)
and isOdd 0 = false
| isOdd 0 = true
| isOdd n = isEven (n - 1)
And an example with datatypes:
datatype 'a exposed = Exposed of 'a * 'a stream
and 'a stream = Stream of unit -> 'a exposed
However, and
is also supported (I presume for consistency's sake?) in some other contexts, where it merely has the effect of introducing all the bindings tied together simultaneously. For instance, in
val x = 7
and y = 8
both x
and y
are introduced at once. To now directly address your immediate examples:
and
instead of val and
t1
in the second---it has not yet been introduced.val
However, all of these also suffer from syntax errors because op
is also a reserved word (it's principally used for allowing infix functions to be treated as prefix functions, like in val sum = foldr op+ 0
). If you change this, leaving you with something like
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
then it should work as intended. I should also note that /
is used for division on real
s, so if you intend to work with int
s instead, it ought to be div
(also infix).