# Simple metaprogramming exercises/challenges

**URL:** https://discourse.julialang.org/t/simple-metaprogramming-exercises-challenges/731
**Category:** New to Julia
**Tags:** metaprogramming
**Created:** [December 4, 2016, 11:31pm UTC](https://discourse.julialang.org/t/simple-metaprogramming-exercises-challenges/731 "2016-12-04T23:31:57Z")
**Posts on this page:** 12
**Page:** 2

<div class="post-metadata">

### Author: ![StefanKarpinski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefankarpinski/32/24_2.png) [@StefanKarpinski](https://discourse.julialang.org/u/StefanKarpinski)
#### Post date: [January 6, 2018, 7:51pm UTC](https://discourse.julialang.org/t/simple-metaprogramming-exercises-challenges/731/21 "2018-01-06T19:51:32Z")

</div>

The `@horner` macro is also cool because it would be so hard to do in a C-like macro system – you really need a full programming language in your macro system.

---

<div class="post-metadata">

### Author: ![rakeshvar](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rakeshvar/32/3613_2.png) [@rakeshvar](https://discourse.julialang.org/u/rakeshvar)
#### Post date: [February 21, 2018, 3:50pm UTC](https://discourse.julialang.org/t/simple-metaprogramming-exercises-challenges/731/22 "2018-02-21T15:50:13Z")

</div>

Here is a challenge: Evaluate a function on a box in `d` dimensional space. Where `d` is not fixed.  
E.g:-

```julia
> @evalongrids println 1:2 1:2 1:2
111
211
.
.

```

My answer is:

```julia
julia> macro evalongrids(fn, grids...)
           variables = [gensym() for g in grids]
           code = :($fn($(variables...)))
           for (v, g) in zip(variables, grids)
             code = :(for $v in $g
                                $code
                           end)
           end
           code
       end
julia> @evalongrids println 1:2 1:2 1:2
111
211
.
.

```

I guess this behaviour can be emulated using `itertools.product` in `python3`.

---

<div class="post-metadata">

### Author: ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)
#### Post date: [February 21, 2018, 3:56pm UTC](https://discourse.julialang.org/t/simple-metaprogramming-exercises-challenges/731/23 "2018-02-21T15:56:12Z")

</div>

Yeah, that needn’t be done with macros — note that you’ll have some hygiene issues if you use that macro outside of a shared global scope.

We also have [`Iterators.product`](https://docs.julialang.org/en/stable/stdlib/iterators/#Base.Iterators.product).

---

<div class="post-metadata">

### Author: ![StefanKarpinski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefankarpinski/32/24_2.png) [@StefanKarpinski](https://discourse.julialang.org/u/StefanKarpinski)
#### Post date: [February 21, 2018, 3:58pm UTC](https://discourse.julialang.org/t/simple-metaprogramming-exercises-challenges/731/24 "2018-02-21T15:58:11Z")

</div>

Showing the macro version first, then the generated function and then the product iterator version is still kind of cool since it mirrors the development history of the language itself and each transition accordingly has a nice “ah, that is better” effect.

---

<div class="post-metadata">

### Author: ![rakeshvar](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rakeshvar/32/3613_2.png) [@rakeshvar](https://discourse.julialang.org/u/rakeshvar)
#### Post date: [February 22, 2018, 7:01am UTC](https://discourse.julialang.org/t/simple-metaprogramming-exercises-challenges/731/25 "2018-02-22T07:01:39Z")

</div>

Agree @StefanKarpinski .  
And most languages do the above using recursion. In fact, Iterators.product also uses recursion.  
In Julia, we can directly write code that will generate variable number of for loops! Which is cool.  
I would love to see the generated function version of it.

---

<div class="post-metadata">

### Author: ![miguelraz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/miguelraz/32/631_2.png) [@miguelraz](https://discourse.julialang.org/u/miguelraz)
#### Post date: [April 6, 2018, 10:45pm UTC](https://discourse.julialang.org/t/simple-metaprogramming-exercises-challenges/731/26 "2018-04-06T22:45:42Z")

</div>

Sorry to chime in, and I know Matt recently gave a similar answer, but is there a more fleshed out post on a concrete example of this evolution and design reflection somewhere? Tracking issues is a bit tricky given the local picture of Julia it can give at the time of development.

---

<div class="post-metadata">

### Author: ![cortner](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cortner/32/204_2.png) [@cortner](https://discourse.julialang.org/u/cortner)
#### Post date: [April 6, 2018, 11:59pm UTC](https://discourse.julialang.org/t/simple-metaprogramming-exercises-challenges/731/27 "2018-04-06T23:59:14Z")

</div>

What if you want a more complicated loop such as

```julia
for i1 = 1:N-2, i2 = i1+1:N-1, i3 = i2+1:N 
end 

```

(with hopefully obvious generalisations)

At the moment I am doing it with `@generated`, which works fine. I feel I could write an iterator, but it is not obvious that it would be simpler or more performant?

---

<div class="post-metadata">

### Author: ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)
#### Post date: [April 7, 2018, 12:44pm UTC](https://discourse.julialang.org/t/simple-metaprogramming-exercises-challenges/731/28 "2018-04-07T12:44:29Z")

</div>

> [@pitao](#):
>
> Could we brainstorm a handful of metaprogramming examples/exercises/challenges?

This tutorial notebook might be helpful: [https://github.com/stevengj/18S096/blob/master/lectures/lecture7/Metaprogramming.ipynb](https://github.com/stevengj/18S096/blob/master/lectures/lecture7/Metaprogramming.ipynb)

Problem set 2 from that seminar has a continued-fraction metaprogramming problem: [https://github.com/stevengj/18S096/tree/iap2017/pset2](https://github.com/stevengj/18S096/tree/iap2017/pset2)

---

<div class="post-metadata">

### Author: ![cscherrer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cscherrer/32/7631_2.png) [@cscherrer](https://discourse.julialang.org/u/cscherrer)
#### Post date: [August 30, 2018, 3:31am UTC](https://discourse.julialang.org/t/simple-metaprogramming-exercises-challenges/731/29 "2018-08-30T03:31:13Z")

</div>

Here’s one I had some trouble with:  
Create a function `mapbody` that applies a function `f` to the body of a function expression `functionExpr`.

My solution:

```julia
function mapbody(f,functionExpr)
    ans = deepcopy(functionExpr)
    ans.args[2] = f(ans.args[2])
    ans
end

```

---

<div class="post-metadata">

### Author: ![Tero\_Frondelius](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tero_frondelius/32/7629_2.png) [@Tero\_Frondelius](https://discourse.julialang.org/u/Tero_Frondelius)
#### Post date: [August 30, 2018, 4:19am UTC](https://discourse.julialang.org/t/simple-metaprogramming-exercises-challenges/731/30 "2018-08-30T04:19:10Z")

</div>

Are you familiar of [GitHub - FluxML/MacroTools.jl: MacroTools provides a library of tools for working with Julia code and expressions.](https://github.com/MikeInnes/MacroTools.jl)? I don’t have my own user experience but I have seen it recommended multiple times. Macros fascinates me and I wish I could find a time to learn to use them.

---

<div class="post-metadata">

### Author: ![cscherrer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cscherrer/32/7631_2.png) [@cscherrer](https://discourse.julialang.org/u/cscherrer)
#### Post date: [August 30, 2018, 4:20am UTC](https://discourse.julialang.org/t/simple-metaprogramming-exercises-challenges/731/31 "2018-08-30T04:20:18Z")

</div>

> [@Tero\_Frondelius](#):
>
> Are you familiar of [GitHub - FluxML/MacroTools.jl: MacroTools provides a library of tools for working with Julia code and expressions.](https://github.com/MikeInnes/MacroTools.jl)?

Yep, that was my original approach but this is much simpler. I often forget going from first principles is even an option 🙂

---

<div class="post-metadata">

### Author: ![Raf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/raf/32/3383_2.png) [@Raf](https://discourse.julialang.org/u/Raf)
#### Post date: [August 30, 2018, 7:35am UTC](https://discourse.julialang.org/t/simple-metaprogramming-exercises-challenges/731/32 "2018-08-30T07:35:17Z")

</div>

Here’s one using recursive @generated functions that I can’t imagine doing in another language:

Aim: A generalised algorithm to walk nested trees of structs and tuples and convert them to and from flat structures.

Conditions:

1. Field handling methods are outside of pure functions so they can be changed by users.
2. Fields may return an empty return value.

General solution:

```julia
# Build a list of expressions wrapped in splats
nested(T::Type, t, expr_builder, handler=default_handler) =  
    handler(T, [Expr(:..., expr_builder(T, t, fn)) for fn in fieldnames(T)])
# Default to wrapping the list of expressions in a tuple
default_handler(T, expressions) = Expr(:tuple, expressions...)

```

An implementation for flattening arbitrary nested structs to a tuple, with a method for types in Number:

```julia
# Expression builder that returns a call to the generated function
flatten_expr(T, t, fn) = :(flatten(getfield($t, $(QuoteNode(fn))))
# The actual generated function just calls nested()
@generated flatten(t) = nested(T, :t, flatten_expr) 
# Method overrides. wrap results in something splattable.
flatten(x::Number) = (x,)

```

You could also use a handler that constructed types to run the process in the opposite direction.

Its hardly long enough to be a package anymore, but:

> **[GitHub - rafaqz/Nested.jl: Build high performance @generated functions over...](https://github.com/rafaqz/Nested.jl/)**
>
> Build high performance @generated functions over nested types - GitHub - rafaqz/Nested.jl: Build high performance @generated functions over nested types

[Previous page](https://discourse.julialang.org/t/simple-metaprogramming-exercises-challenges/731.md?page=1)
