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: docs/src/manual/rewrite.md
+42-11Lines changed: 42 additions & 11 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -25,34 +25,34 @@ r1(sin(2z))
25
25
26
26
The `@rule` macro takes a pair of patterns -- the _matcher_ and the _consequent_ (`@rule matcher => consequent`). If an expression matches the matcher pattern, it is rewritten to the consequent pattern. `@rule` returns a callable object that applies the rule to an expression.
27
27
28
-
`~x` in the example is what is a **slot variable** named `x`. In a matcher pattern, slot variables are placeholders that match exactly one expression. When used on the consequent side, they stand in for the matched expression. If a slot variable appears twice in a matcher pattern, all corresponding matches must be equal (as tested by `Base.isequal` function). Hence this rule says: if you see something added to itself, make it twice of that thing, and works as such.
28
+
`~x` in the example is what is a **slot variable** named `x`. In a matcher pattern, slot variables are placeholders that match exactly one expression. When used on the consequent side, they stand in for the matched expression. If a slot variable appears twice in a matcher pattern, all corresponding matches must be equal (as tested by `Base.isequal` function).
29
29
30
30
If you try to apply this rule to an expression with triple angle, it will return `nothing` -- this is the way a rule signifies failure to match.
31
-
```jldoctest rewrite
32
-
r1(sin(3z)) === nothing
31
+
```julia
32
+
r1(sin(3z))
33
33
34
34
# output
35
-
true
35
+
nothing
36
36
```
37
37
38
-
Slot variable (matcher) is not necessary a single variable
39
-
38
+
Slot variable (matcher) is not necessary a single variable:
40
39
```jldoctest rewrite
41
40
r1(sin(2*(w-z)))
42
41
43
42
# output
44
43
2cos(w - z)*sin(w - z)
45
44
```
46
45
47
-
but it must be a single expression
46
+
And can also match a function:
47
+
```julia
48
+
r =@rule (~f)(z+1) =>~f
48
49
49
-
```jldoctest rewrite
50
-
r1(sin(2*(w+z)*(α+β))) === nothing
50
+
r(sin(z+1))
51
51
52
52
# output
53
-
true
54
-
```
53
+
sin (generic function with 20 methods)
55
54
55
+
```
56
56
Rules are of course not limited to single slot variable
57
57
58
58
```jldoctest rewrite
@@ -64,6 +64,37 @@ r2(sin(α+β))
64
64
sin(β)*cos(α) + cos(β)*sin(α)
65
65
```
66
66
67
+
Now let's say you want to catch the coefficients of a second degree polynomial in z. You can do that with:
68
+
```jldoctest rewrite
69
+
c2d = @rule ~a + ~b*z + ~c*z^2 => (~a, ~b, ~c)
70
+
71
+
c2d(3 + 2z + 5z^2)
72
+
# output
73
+
(3, 2, 5)
74
+
```
75
+
Great! But if you try:
76
+
```julia
77
+
c2d(3+2z + z^2)
78
+
79
+
#output
80
+
nothing
81
+
```
82
+
the rule is not applied. This is because in the input polynomial there isn't a multiplication in front of the `z^2`. For this you can use **defslot variables**, with syntax `~!a`:
83
+
```jldoctest rewrite
84
+
c2d = @rule ~!a + ~!b*z + ~!c*z^2 => (~a, ~b, ~c)
85
+
86
+
c2d(3 + 2z + z^2)
87
+
# output
88
+
(3, 2, 1)
89
+
```
90
+
They work like normal slot variables, but if they are not present they take a default value depending on the operation they are in, in the above example `~b = 1`. Currently defslot variables can be defined in:
91
+
92
+
Operation | Default value
93
+
----------|--------------
94
+
multiplication `*` | 1
95
+
addition `+` | 0
96
+
2nd argument of `^` | 1
97
+
67
98
If you want to match a variable number of subexpressions at once, you will need a **segment variable**. `~~xs` in the following example is a segment variable:
Copy file name to clipboardExpand all lines: src/rule.jl
+23-22Lines changed: 23 additions & 22 deletions
Original file line number
Diff line number
Diff line change
@@ -248,24 +248,6 @@ If an expression matches LHS entirely, then it is rewritten to the pattern in th
248
248
Slot, DefSlot and Segment variables on the RHS will substitute the result of the
249
249
matches found for these variables in the LHS.
250
250
251
-
If the RHS is a single tilde `~`, then the rule returns a a dictionary of
252
-
[slot variable, expression matched].
253
-
254
-
_Example:_
255
-
256
-
```julia
257
-
julia> r = @rule (~x + (~y)^(~m)) => ~
258
-
~x + (~y) ^ ~m => (~)
259
-
260
-
julia> r(a + b^2)
261
-
Base.ImmutableDict{Symbol, Any} with 5 entries:
262
-
:MATCH => a + b^2
263
-
:m => 2
264
-
:y => b
265
-
:x => a
266
-
:____ => nothing
267
-
```
268
-
269
251
**Slot**:
270
252
271
253
A Slot variable is written as `~x` and matches a single expression. `x` is the name of the variable. If a slot appears more than once in an LHS expression then expression matched at every such location must be equal (as shown by `isequal`).
A DefSlot variable is written as `~!x`. Works like a normal slot, but can also take additional values if not present in the expression.
295
+
A DefSlot variable is written as `~!x`. Works like a normal slot, but can also take default values if not present in the expression.
314
296
315
297
_Example in power:_
316
298
```julia
@@ -337,10 +319,11 @@ julia> r_sum(x)
337
319
```
338
320
339
321
Currently DefSlot is implemented in:
340
-
Operation | Default value
322
+
323
+
Operation | Default value<br>
341
324
----------|--------------
342
-
* | 1
343
-
+ | 0
325
+
\\* | 1
326
+
\\+ | 0
344
327
2nd argument of ^ | 1
345
328
346
329
**Segment**:
@@ -410,6 +393,24 @@ true
410
393
Note that this is syntactic sugar and that it is the same as something like
411
394
`@rule ~x => f(~x) ? ~x : nothing`.
412
395
396
+
**Debugging Rules**:
397
+
Note that if the RHS is a single tilde `~`, then the rule returns a a dictionary of all [slot variable, expression matched], this is useful for debugging.
398
+
399
+
_Example:_
400
+
401
+
```julia
402
+
julia> r = @rule (~x + (~y)^(~m)) => ~
403
+
~x + (~y) ^ ~m => (~)
404
+
405
+
julia> r(a + b^2)
406
+
Base.ImmutableDict{Symbol, Any} with 5 entries:
407
+
:MATCH => a + b^2
408
+
:m => 2
409
+
:y => b
410
+
:x => a
411
+
:____ => nothing
412
+
```
413
+
413
414
**Context**:
414
415
415
416
_In predicates_: Contextual predicates are functions wrapped in the `Contextual` type.
0 commit comments