You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: courses/RascalAmendmentProposals/RAP15/RAP15.md
+34-15Lines changed: 34 additions & 15 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -17,27 +17,33 @@ The proposal is to extend the Pattern notation like so:
17
17
18
18
The semantics is that if the `pattern` matches then we check if the boolean `condition` evaluates to true in the current environment (which includes optional bindings from the current pattern).
19
19
20
-
And to introduce short-hand notation for all binary predicate operators (==, \!=, :=, \!:=, \<, \<=, \>=, \>) like so:
The `when` notation and semantics could be completely removed in time.
32
+
28
33
## Motivation
29
34
30
35
This RAP solves *a number of issues* in the design of Rascal’s syntax and semantics in one go:
31
36
32
37
***Non-linear patterns (reused pattern variables)** often accidentally capture variables of the outer scope, leading to unexpected failure. This is one of the oldest issues in the design and has been mitigated by the checker providing info/warnings when it happens.
33
-
* When-clauses are written out of the execution order
34
-
* When-clauses are not allowed for functions with statement blocks as bodies
35
-
* Randomized input for tests has to be filtered inside of tests, often returning `true` when the test input is invalid (and wasting opportunity for the valid input).
38
+
***When-clauses are written out of the execution order**
39
+
***When-clauses are not allowed for functions with statement blocks as bodies**
40
+
* Randomized input for tests has to be filtered inside of tests code block, often returning `true` when the test input is invalid (and wasting opportunity for the valid inputs).
36
41
37
-
The urgency of this RAP is *low*. However, the non-linear matching issue has waited for more than 10 years now and it is still a weekly cause of time loss debugging this trivial issue in new code.
42
+
The urgency of this RAP is *low*. However, the non-linear matching issue has **waited for more than 10 years now** and it is still a weekly cause of time loss debugging this trivial issue in new code. The type-checker warns about non-linear matches with an info message; which helps while writing new code, but it is a frequent source of false positives in the code that is left.
38
43
39
-
Also there are other ways to solve the nonlinear matching problem. For example by introducing specific syntax for it in the Pattern notation. The benefit of this new notation is that it fixes the non-linear matching problem but also other problems with “when” and with random tests.
44
+
There are other ways to solve the nonlinear matching problem than to rename a variable. For example by introducing specific syntax for equality testing in the Pattern notation.
40
45
46
+
The benefit of the currently proposed new notation is that it fixes the non-linear matching problem but also other problems with “when” and with random tests.
41
47
**It would be less nice if we have to add conditional patterns anyway and have added yet another syntax for non-linear matching.**
42
48
43
49
## Specification
@@ -54,7 +60,7 @@ Dynamic semantics:
54
60
55
61
* First the pattern is matched against the current subject; with optional bindings as a side-effect. Note that if the pattern is not singular, backtracking may occur later.
56
62
* Then a new backtracking and binding scope is wrapped around the evaluation of the condition (such that complex back-tracking conditions can introduce variables and be cleaned up nicely)
57
-
* The condition finds the first way to evaluate to true (includes possible backtracking over the original pattern, but certainly also over non-singular parameters of && and ||.
63
+
* The condition finds the first way to evaluate to true (includes possible backtracking over the original pattern, but certainly also over non-singular parameters of `&&` and `||`. The semantics is comparable to the sematics of a `when` clause.
58
64
* If there is no way to evaluate the condition to true, the entire pattern fails.
59
65
* Otherwise the pattern succeeds and continues with the bindings introduced by the pattern side (and drops the new bindings introduced by the condition side).
60
66
@@ -67,25 +73,37 @@ Test semantics
67
73
68
74
Short-hand notation
69
75
70
-
* Expanding `p == v` to `tmp:p if tmp == v` for every binary operator is simple.
71
-
* Note how `_ == a` and `b := a` can be used for two different types of non-linear match. The first matches with equality (including keyword fields). The second matches with equality-modulo-keyword fields.
76
+
* Expanding `p == v` to `tmp:p if tmp == v` for every binary operator. `tmp` must be fresh in the current scope, and unused in the succeeding scopes.
77
+
* Note how `_ == a` and `_ := a` can be used for two different types of non-linear match. The first matches with equality (including keyword fields). The second matches with equality-modulo-keyword fields.
72
78
73
79
New static restrictions on patterns:
74
80
75
81
* Implicit nonlinear patterns are “duplicate declaration” errors:
76
-
* so: `and(x, x)` is and error (second x is a duplicate declaration
82
+
* so: `and(x, x)` is and error (second x is a duplicate declaration). Initially this should be a warning (not an info anymore) and a quickfix should be generated to expand the non-linear match to either `_ := x` or `_ == x`
77
83
* Should be written as `and(x, _ := x) or and(x, _ == x)`
78
84
* All variable introductions in patterns are “fresh” from now on, so the static semantics of:
79
85
*`int x` is the same as
80
86
*`x`
81
87
* Except for the possibility of type inference in the latter.
82
88
89
+
Removing `when`
90
+
91
+
* Any application of when can always be rewriting to an application of `if` to the last parameter.
92
+
* If an `if` uses only variables to the left, then it can be moved to earlier in the parameter list.
93
+
* Only `when` clauses to functions without parameters can not be transformed,
94
+
however, we are pretty sure that those do not exist. In any case they could be rewrittten to an `if` inside the body of the function or a `?:` expression.
95
+
83
96
## Examples
84
97
85
98
```
86
-
// "dependent types"
99
+
// simulating "dependently typed patterns"
100
+
// because pattern matching is a runtime feature, we are no actually
101
+
// introducing a dependently typed type-system (!) but we come close
102
+
// to the same level of expressiveness.
87
103
int fac(0) = 1;
88
104
int fac(int n > 0) = fac(n - 1) * n;
105
+
// without use of the shorthand:
106
+
int fac(int n if n > 0) = fac(n - 1) * n;
89
107
90
108
bool evenOdd(int E if E % 2 == 0,
91
109
int O if E % 2 == 1) = true;
@@ -106,9 +124,10 @@ This simplifies the implementation of the type-checker and the interpreter alike
106
124
1. change the current informational message on nonlinear matches to a warning with suggestion for refactoring.
107
125
2. Add warnings for all “when” clauses to be refactored to conditional patterns (if possible)
108
126
3. Add warnings for tests that use `==>` for input filtering or `if(expression) return true;`
127
+
4. Add simple quick-fixes to the warnings
109
128
3. Then, in time, we remove the old semantics:
110
129
1. Make non-linear matches produce double declaration errors
0 commit comments