#pattern-matching #sml #ml
#сопоставление с образцом #sml #ml
Вопрос:
Могу ли я в sml использовать кортеж в a let
? Если да, то каким будет синтаксис? Я могу потребовать, чтобы это соответствовало концентрическому шаблону, но, похоже, должен быть менее шаблонный способ. В приведенном let
ниже примере я хотел бы привязать v1
and 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,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
При дальнейших экспериментах я обнаружил еще один синтаксис, но я не уверен, в чем разница, т. Е. Использование val
, а не and
в 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
Ответ №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
оба 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
s, поэтому, если вы собираетесь работать с int
s вместо этого, оно должно быть div
(также инфиксным).
Комментарии:
1. Спасибо за объяснение.
op
Я не ожидал, что это зарезервированное слово; новичку довольно сложно разобраться. И спасибо за комментарий о/
vsdiv
.