Does Rascal support pattern guards?
I'm trying to order subexpressions on build:
data Expr = and(Expr l, Expr r) | ... ;
Expr and(l, r) | r < l = and(r, l); // fictional syntax for "r < l" guard
If guards are unsupported, what's the best way to implement the above?
Just to simplify things I've used int
as the type for l
and r
at first. What you want to do is something like the following:
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)
If you create a function with the same name as the constructor that returns the data type you are defining (e.g., Expr
), this will allow you to do this kind of canonicalization. The when
clause says to only apply the function when the condition matches. You could have a more complex condition, so if you had Expr
instead as the type of the fields you could have a function like eval
that actually evaluates an expression and returns a result. A partial example of this (which assumes you only have one level of nesting) is the following:
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))
To use when
, you need to use this expression form of a function, where you have an =
sign and the return value. If you have a more complex computation in the canonicalization, you can instead do something like the following:
Expr and(int l, int r) {
if (r < l) {
return and(r,l);
} else {
fail;
}
}
This essentially does the same thing. If the condition is met, a new version of and
is returned. If the condition is not met, fail
is used to indicate that we don't actually want to apply this function, so the initial value will be returned:
rascal>and(5,6);
Expr: and(5,6)
rascal>and(6,5);
Expr: and(5,6)