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: CHANGELOG.md
+47
Original file line number
Diff line number
Diff line change
@@ -1,3 +1,50 @@
1
+
# v0.6
2
+
3
+
**Breaking**: The rules for transforming chains were simplified.
4
+
Before, there was the two-arg block syntax (this was the only syntax originally):
5
+
6
+
```julia
7
+
@chain x begin
8
+
y
9
+
z
10
+
end
11
+
```
12
+
13
+
the inline syntax:
14
+
15
+
```julia
16
+
@chain x y z
17
+
```
18
+
19
+
and the one-arg block syntax:
20
+
21
+
```julia
22
+
@chainbegin
23
+
x
24
+
y
25
+
z
26
+
end
27
+
```
28
+
All of these are now a single syntax, derived from the rule that any `begin ... end` block in the inline syntax is flattened into its lines.
29
+
This means that you can also use multiple `begin ... end` blocks, and they can be in any position, which can be nice for interactive development of a chain in the REPL.
30
+
31
+
```julia
32
+
@chain x y begin
33
+
x
34
+
y
35
+
z
36
+
end u v w begin
37
+
g
38
+
h
39
+
i
40
+
end
41
+
```
42
+
43
+
This is only breaking if you were using a `begin ... end` block in the inline syntax at argument 3 or higher, but you also had to be using an underscore without chaining in that begin block, which is deemed quite unlikely given the intended use of the package.
44
+
All "normal" usage of the `@chain` macro should work as it did before.
45
+
46
+
As another consequence of the refactor, chains now do not error anymore for a single argument form `@chain x` but simply return `x`.
47
+
1
48
# v0.5
2
49
3
50
**Breaking**: The `@chain` macro now creates a `begin` block, not a `let` block.
Copy file name to clipboardExpand all lines: README.md
+87-92
Original file line number
Diff line number
Diff line change
@@ -67,131 +67,150 @@ end
67
67
68
68
## Summary
69
69
70
-
Chain.jl defines the `@chain` macro. It takes a start value and a `begin ... end` block of expressions.
70
+
Chain.jl exports the `@chain` macro.
71
71
72
-
The result of each expression is fed into the next one using one of two rules:
72
+
This macro rewrites a series of expressions into a chain, where the result of one expression
73
+
is inserted into the next expression following certain rules.
73
74
74
-
1.**There is at least one underscore in the expression**
75
-
- every `_` is replaced with the result of the previous expression
76
-
2.**There is no underscore**
77
-
- the result of the previous expression is used as the first argument in the current expression, as long as it is a function call, a macro call or a symbol representing a function.
75
+
**Rule 1**
78
76
79
-
Lines that are prefaced with `@aside` are executed, but their result is not fed into the next pipeline step.
80
-
This is very useful to inspect pipeline state during debugging, for example.
77
+
Any `expr` that is a `begin ... end` block is flattened.
78
+
For example, these two pseudocodes are equivalent:
81
79
82
-
## Motivation
80
+
```julia
81
+
@chain a b c d e f
83
82
84
-
- The implicit first argument insertion is useful for many data pipeline scenarios, like `groupby`, `transform` and `combine` in DataFrames.jl
85
-
- The `_` syntax is there to either increase legibility or to use functions like `filter` or `map` which need the previous result as the second argument
86
-
- There is no need to type `|>` over and over
87
-
- Any line can be commented out or in without breaking syntax, there is no problem with dangling `|>` symbols
88
-
- The state of the pipeline can easily be checked with the `@aside` macro
89
-
- The `begin ... end` block marks very clearly where the macro is applied and works well with auto-indentation
90
-
- Because everything is just lines with separate expressions and not one huge function call, IDEs can show exactly in which line errors happened
91
-
- Pipe is a name defined by Base Julia which can lead to conflicts
83
+
@chain a begin
84
+
b
85
+
c
86
+
d
87
+
end e f
88
+
```
92
89
93
-
## Example
90
+
**Rule 2**
94
91
95
-
An example with a DataFrame:
92
+
Any expression but the first (in the flattened representation) will have the preceding result
93
+
inserted as its first argument, unless at least one underscore `_` is present.
94
+
In that case, all underscores will be replaced with the preceding result.
96
95
97
-
```julia
98
-
using DataFrames, Chain
96
+
If the expression is a symbol, the symbol is treated equivalently to a function call.
localvar"##4"=combine(var"##3", :weight=> sum =>:total_weight)
115
+
begin
116
+
local temp1 =f(x)
117
+
local temp2 =@g(temp1)
118
+
local temp3 =h(temp2)
119
+
local temp4 =@i(temp3)
120
+
local temp5 =j(123, temp4)
121
+
local temp6 =k(temp5, 123, temp5)
118
122
end
119
123
```
120
124
121
-
## Alternative one-argument syntax
125
+
**Rule 3**
122
126
123
-
If your initial argument name is long and / or the chain's result is assigned to a long variable, it can look cleaner if the initial value is moved into the chain.
124
-
Here is such a long expression:
127
+
An expression that begins with `@aside` does not pass its result on to the following expression.
128
+
Instead, the result of the previous expression will be passed on.
129
+
This is meant for inspecting the state of the chain.
130
+
The expression within `@aside` will not get the previous result auto-inserted, you can use
131
+
underscores to reference it.
125
132
126
133
```julia
127
-
a_long_result_variable_name =@chain a_long_input_variable_name begin
128
-
do_something
129
-
do_something_else(parameter)
130
-
do_other_thing(parameter, _)
134
+
@chainbegin
135
+
[1, 2, 3]
136
+
filter(isodd, _)
137
+
@aside@info"There are \$(length(_)) elements after filtering"
138
+
sum
131
139
end
132
140
```
133
141
134
-
This is equivalent to the following expression:
142
+
**Rule 4**
143
+
144
+
It is allowed to start an expression with a variable assignment.
145
+
In this case, the usual insertion rules apply to the right-hand side of that assignment.
146
+
This can be used to store intermediate results.
135
147
136
148
```julia
137
-
a_long_result_variable_name =@chainbegin
138
-
a_long_input_variable_name
139
-
do_something
140
-
do_something_else(parameter)
141
-
do_other_thing(parameter, _)
149
+
@chainbegin
150
+
[1, 2, 3]
151
+
filtered =filter(isodd, _)
152
+
sum
142
153
end
154
+
155
+
filtered == [1, 3]
143
156
```
144
157
145
-
## One-liner syntax
158
+
**Rule 5**
146
159
147
-
You can also use `@chain` as a one-liner, where no begin-end block is necessary.
148
-
This works well for short sequences that are still easy to parse visually without being on separate lines.
160
+
The `@.` macro may be used with a symbol to broadcast that function over the preceding result.
149
161
150
162
```julia
151
-
@chain1:10filter(isodd, _) sum sqrt
163
+
@chainbegin
164
+
[1, 2, 3]
165
+
@. sqrt
166
+
end
152
167
```
153
168
154
-
## Variable assignments in the chain
155
-
156
-
You can prefix any of the expressions that Chain.jl can handle with a variable assignment.
157
-
The previous value will be spliced into the right-hand-side expression and the result will be available afterwards under the chosen variable name.
169
+
is equivalent to
158
170
159
171
```julia
160
-
@chain1:10begin
161
-
_ *3
162
-
filtered =filter(iseven, _)
163
-
sum
172
+
@chainbegin
173
+
[1, 2, 3]
174
+
sqrt.(_)
164
175
end
165
-
166
-
filtered == [6, 12, 18, 24, 30]
167
176
```
168
177
169
-
## The `@aside` macro
170
178
171
-
For debugging, it's often useful to look at values in the middle of a pipeline.
172
-
You can use the `@aside` macro to mark expressions that should not pass on their result.
173
-
For these expressions there is no implicit first argument spliced in if there is no `_`, because that would be impractical for most purposes.
179
+
## Motivation
174
180
175
-
If for example, we wanted to know how many groups were created after step 3, we could do this:
181
+
- The implicit first argument insertion is useful for many data pipeline scenarios, like `groupby`, `transform` and `combine` in DataFrames.jl
182
+
- The `_` syntax is there to either increase legibility or to use functions like `filter` or `map` which need the previous result as the second argument
183
+
- There is no need to type `|>` over and over
184
+
- Any line can be commented out or in without breaking syntax, there is no problem with dangling `|>` symbols
185
+
- The state of the pipeline can easily be checked with the `@aside` macro
186
+
- Flattening of `begin ... end` blocks allows you to split your chain over multiple lines
187
+
- Because everything is just lines with separate expressions and not one huge function call, IDEs can show exactly in which line errors happened
188
+
- Pipe is a name defined by Base Julia which can lead to conflicts
0 commit comments