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
@@ -43,10 +43,10 @@ Testing it gives us the expected behavior
43
43
@myshow xx = 1 + 1
44
44
xx # should be defined
45
45
```
46
-
In this "simple" example, we had to use the following concepts mentioned already in the lecture:
47
-
-`QuoteNode(ex)` is used to wrap the expression inside another layer of quoting, such that when it is interpolated into `:()` it stays being a piece of code instead of the value it represents - **TRUE QUOTING**
48
-
-`esc(ex)` is used in case that the expression contains an assignment, that has to be evaluated in the top level module `Main` (we are `esc`aping the local context) - **ESCAPING**
49
-
-`$(QuoteNode(ex))` and `$(esc(ex))` is used to evaluate an expression into another expression. **INTERPOLATION**
46
+
In this "simple" example, we had to use the following concepts mentioned already in the [lecture](@ref macro_lecture):
47
+
-`QuoteNode(ex)` is used to wrap the expression inside another layer of quoting, such that when it is interpolated into `:()` it stays being a piece of code instead of the value it represents - [**TRUE QUOTING**](@ref lec7_quotation)
48
+
-`esc(ex)` is used in case that the expression contains an assignment, that has to be evaluated in the top level module `Main` (we are `esc`aping the local context) - [**ESCAPING**](@ref lec7_hygiene)
49
+
-`$(QuoteNode(ex))` and `$(esc(ex))` is used to evaluate an expression into another expression. [**INTERPOLATION**](@ref lec7_quotation)
50
50
-`local value = ` is used in order to return back the result after evaluation
51
51
52
52
Lastly, let's mention that we can use `@macroexpand` to see how the code is manipulated in the `@myshow` macro
@@ -83,7 +83,9 @@ _repeat(3, :(println("Hello!"))) # testing "macro" without defining it
83
83
```
84
84
85
85
**HINTS**:
86
-
- use `$` interpolation into a for loop expression
86
+
- use `$` interpolation into a for loop expression; for example given `ex = :(1+x)` we can interpolate it into another expression `:($ex + y)` -> `:(1 + x + y)`
87
+
- if unsure what gets interpolated use round brackets `:($(ex) + y)`
88
+
- macro is a function that *creates* code that does what we want
87
89
88
90
**BONUS**:
89
91
What happens if we call `@repeat 3 x = 2`? Is `x` defined?
@@ -123,12 +125,14 @@ Ideally we would like write some macro `@poly` that takes a polynomial in a math
123
125
*Example usage*:
124
126
```julia
125
127
p =@poly x 3x^2+2x^1+10x^0# the first argument being the independent variable to match
128
+
p(2) # return the value
126
129
```
127
130
128
131
However in order to make this happen, let's first consider much simpler case of creating the same but without the need for parsing the polynomial as a whole and employ the fact that macro can have multiple arguments separated by spaces.
129
132
130
133
```julia
131
134
p =@poly3210
135
+
p(2)
132
136
```
133
137
134
138
```@raw html
@@ -138,10 +142,29 @@ p = @poly 3 2 10
138
142
```
139
143
Create macro `@poly` that takes multiple arguments and creates an anonymous function that constructs the unrolled code. Instead of directly defining the macro inside the macro body, create helper function `_poly` with the same signature that can be reused outside of it.
140
144
145
+
Recall Horner's method polynomial evaluation from previous [labs](@ref horner):
[^1]: Explanation of the Horner schema can be found on [https://en.wikipedia.org/wiki/Horner%27s\_method](https://en.wikipedia.org/wiki/Horner%27s_method).
147
170
```@raw html
@@ -151,6 +174,7 @@ Create macro `@poly` that takes multiple arguments and creates an anonymous func
151
174
```
152
175
153
176
```@repl lab07_poly
177
+
using InteractiveUtils #hide
154
178
macro poly(a...)
155
179
return _poly(a...)
156
180
end
@@ -182,7 +206,7 @@ Moving on to the first/harder case, where we need to parse the mathematical expr
182
206
```
183
207
Create macro `@poly` that takes two arguments first one being the independent variable and second one being the polynomial written in mathematical notation. As in the previous case this macro should define an anonymous function that constructs the unrolled code.
184
208
```julia
185
-
julia> p =@poly x 3x^2+2x^1+10x^0# the first argument being the independent variable to match
209
+
julia> p =@poly x 3x^2+2x^1+10x^0# the first argument being the independent variable to match
186
210
```
187
211
188
212
**HINTS**:
@@ -262,7 +286,6 @@ end
262
286
```
263
287
Let's test it.
264
288
```@repl lab07_poly
265
-
using InteractiveUtils #hide
266
289
p = @poly x 3x^2+2x^1+ 10
267
290
p(2) == evalpoly(2, [10,2,3])
268
291
@code_lowered p(2) # can show the generated code
@@ -357,6 +380,9 @@ Unfortunately the current version of `Ecosystem` and `EcosystemCore`, already co
@@ -369,14 +395,24 @@ Based on the following example syntax,
369
395
@species Plant Broccoli 🥦
370
396
@species Animal Rabbit 🐇
371
397
```
372
-
write macro `@species` inside `Ecosystem` pkg, which defines the abstract type, its show function and exports the type.
373
-
374
-
Define first helper function `_species` to inspect the macro's output. This is indispensable, as we are defining new types/constants and thus we would otherwise encountered errors during repeated evaluation (though only if the type signature changed).
398
+
write macro `@species` inside `Ecosystem` pkg, which defines the abstract type, its show function and exports the type. For example `@species Plant Broccoli 🥦` should generate code:
399
+
```julia
400
+
abstract type Broccoli <:PlantSpeciesend
401
+
Base.show(io::IO,::Type{Broccoli}) =print(io,"🥦")
402
+
export Broccoli
403
+
```
404
+
Define first helper function `_species` to inspect the macro's output. This is indispensable, as we are defining new types/constants and thus we may otherwise encounter errors during repeated evaluation (though only if the type signature changed).
405
+
```julia
406
+
_species(:Plant, :Broccoli, :🥦)
407
+
_species(:Animal, :Rabbit, :🐇)
408
+
```
375
409
376
410
**HINTS**:
377
411
- use `QuoteNode` in the show function just like in the `@myshow` example
378
-
- ideally these changes should be made inside the modified `Ecosystem` pkg provided in the lab (though not everything can be refreshed with `Revise`)
412
+
- escaping `esc` is needed for the returned in order to evaluate in the top most module (`Ecosystem`/`Main`)
413
+
- ideally these changes should be made inside the modified `Ecosystem` pkg provided in the lab (though not everything can be refreshed with `Revise`) - there is a file `ecosystem_macros.jl` just for this purpose
379
414
- multiple function definitions can be included into a `quote end` block
415
+
- interpolation works with any expression, e.g. `$(typ == :Animal ? AnimalSpecies : PlantSpecies)`
380
416
381
417
**BONUS**:
382
418
Based on `@species` define also macros `@animal` and `@plant` with two arguments instead of three, where the species type is implicitly carried in the macro's name.
@@ -432,8 +468,9 @@ Define macro `@eats` inside `Ecosystem` pkg that assigns particular species thei
432
468
where `Grass => 0.5` defines the behavior of the `eat!` function. The coefficient is used here as a multiplier for the energy balance, in other words the `Rabbit` should get only `0.5` of energy for a piece of `Grass`.
433
469
434
470
**HINTS**:
435
-
- ideally these changes should be made inside the modified `Ecosystem` pkg provided in the lab (though not everything can be refreshed with `Revise`)
436
-
- you can create an empty `quote end` block with `code = Expr(:block)` and push new expressions incrementally
471
+
- ideally these changes should be made inside the modified `Ecosystem` pkg provided in the lab (though not everything can be refreshed with `Revise`) - there is a file `ecosystem_macros.jl` just for this purpose
472
+
- escaping `esc` is needed for the returned in order to evaluate in the top most module (`Ecosystem`/`Main`)
473
+
- you can create an empty `quote end` block with `code = Expr(:block)` and push new expressions into its `args` incrementally
437
474
- use dispatch to create specific code for the different combinations of agents eating other agents (there may be catch in that we have to first `eval` the symbols before calling in order to know if they are animals or plants)
438
475
439
476
!!! note "Reminder of `EcosystemCore``eat!` and `eats` functionality"
@@ -512,10 +549,10 @@ _eats(species, foodlist)
512
549
```
513
550
514
551
---
515
-
# Resources
552
+
##Resources
516
553
- macros in Julia [documentation](https://docs.julialang.org/en/v1/manual/metaprogramming/#man-macros)
517
554
518
-
## `Type{T}` type selectors
555
+
###`Type{T}` type selectors
519
556
We have used `::Type{T}` signature[^2] at few places in the `Ecosystem` family of packages (and it will be helpful in the HW as well), such as in the `show` methods
0 commit comments