Просто для упрощения вещей я использовал int
как тип для l
и r
сперва. То, что вы хотите сделать что-то вроде следующего:
rascal>data Expr = and(int l, int r);
ok
rascal>Expr and(int l, int r) = and(r,l) when r < l;
Expr (int, int): rascalfunction()
rascal>and(5,6);
Expr: and(5,6)
rascal>and(6,5);
Expr: and(5,6)
Если вы создаете функцию с тем же именем, что и конструктор, который возвращает тип данных, определяемый вами (например, Expr
), это позволит вам сделать этот вид канонизации. В предложении when
говорится, что применяется только при выполнении условия. У вас может быть более сложное условие, поэтому, если бы у вас было Expr
, вместо этого в качестве типа полей вы могли бы иметь такую функцию, как eval
, которая фактически оценивает выражение и возвращает результат. Частичный пример этого (что предполагает у вас есть только один уровень вложенности) заключается в следующем:
rascal>data Expr = number(int n) | and(Expr l, Expr r);
ok
rascal>int eval(number(int n)) = n;
int (Expr): rascalfunction()
rascal>Expr and(Expr l, Expr r) = and(r,l) when eval(r) < eval(l);
Expr (Expr, Expr): rascalfunction()
rascal>and(number(5),number(6));
Expr: and(
number(5),
number(6))
rascal>and(number(6),number(5));
Expr: and(
number(5),
number(6))
Чтобы использовать when
, вы должны использовать это выражение вид функции, где Вы состоите =
знак и возвращаемое значение. Если у вас есть более сложные вычисления в канонизации, вы можете вместо этого сделать что-то вроде следующего:
Expr and(int l, int r) {
if (r < l) {
return and(r,l);
} else {
fail;
}
}
Это по существу делает то же самое. Если условие выполнено, возвращается новая версия and
. Если условие не выполняется, fail
используется для указания того, что в действительности мы не хотим, чтобы применить эту функцию, поэтому начальное значение будет возвращено:
rascal>and(5,6);
Expr: and(5,6)
rascal>and(6,5);
Expr: and(5,6)
'when' и' fail' являются именно то, что мне нужно , благодаря. –
Я бы рекомендовал всегда использовать 'fail и; 'вместо plain' fail', потому что 'fail' лексически привязан к самому внутреннему ошибочному контексту (например, к if-ветви или к телу цикла for). В случае 'else' это необязательно, так как внутренний наиболее ошибочный контекст является самой функцией. 'fail' с меткой позволяет вам перейти к внешнему ошибочному контексту (в данном случае' 'и' функция '). – jurgenv