# 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:** 20
**Page:** 1

<div class="post-metadata">

### Author: ![pitao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pitao/32/116_2.png) [@pitao](https://discourse.julialang.org/u/pitao)
#### Post date: [December 4, 2016, 11:31pm UTC](https://discourse.julialang.org/t/simple-metaprogramming-exercises-challenges/731/1 "2016-12-04T23:31:57Z")

</div>

Could we brainstorm a handful of metaprogramming examples/exercises/challenges?

- practical or absurd, both welcome
- with or without solutions, both welcome
- support explanations welcome

The idea is ‘Learning through Doing’.

Here is an example (Thanks @fcard):

```julia
# Write a 'swap_args' macro that reverses operands for simple
# `<a> <op> <b>` expressions, so ` @swap_args(2/3)` gives 1.5 i.e. 3/2
macro swap_args(e)
    e.args[2:3] = e.args[3:-1:2]   
    e
end
@swap_args(2/3)
1.50

```

I will write up a compendium over the next few days and link it at the top of the WikiBook metaprogramming page: [Introducing Julia/Metaprogramming - Wikibooks, open books for an open world](https://en.wikibooks.org/wiki/Introducing_Julia/Metaprogramming).

(EDIT:) Looks like we’re getting a good mix of difficulty levels!

π

---

<div class="post-metadata">

### Author: ![JeffreySarnoff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeffreysarnoff/32/1980_2.png) [@JeffreySarnoff](https://discourse.julialang.org/u/JeffreySarnoff)
#### Post date: [December 6, 2016, 3:58am UTC](https://discourse.julialang.org/t/simple-metaprogramming-exercises-challenges/731/2 "2016-12-06T03:58:20Z")

</div>

Maybe call that one `swap_operands` (because `swap(a,b)` is likely `b,a` without the operator) .

---

<div class="post-metadata">

### Author: ![dfdx](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dfdx/32/120_2.png) [@dfdx](https://discourse.julialang.org/u/dfdx)
#### Post date: [December 6, 2016, 2:12pm UTC](https://discourse.julialang.org/t/simple-metaprogramming-exercises-challenges/731/3 "2016-12-06T14:12:50Z")

</div>

Another common macro that I often describe to newcomers is `@time`.

More sophisticated examples of expression transformations may include functions / macros to match expression against pattern or substitute part of expression, e.g.:

```julia
expr = :(num ^ 2)
pattern = :(x ^ n)
matchex(expr, pattern) # ==> Dict(:x => :num, :n => 2)

expr = :(x ^ n)
subs(expr, n=2) # ==> :(x ^ 2) 

```

I used these functions extensively in [Espresso.jl](https://github.com/dfdx/Espresso.jl), but I find them a funny exercise metaprogramming as well.

---

<div class="post-metadata">

### Author: ![bramtayl](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bramtayl/32/3614_2.png) [@bramtayl](https://discourse.julialang.org/u/bramtayl)
#### Post date: [December 6, 2016, 4:13pm UTC](https://discourse.julialang.org/t/simple-metaprogramming-exercises-challenges/731/4 "2016-12-06T16:13:34Z")

</div>

Chaining macros? A simple one below:

```julia
link(a, b) = quote
    let _ = $a
        b
    end
end

macro chain(as...) = reduce(link, as)

```

```julia

```

---

<div class="post-metadata">

### Author: ![Balinus](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/balinus/32/243_2.png) [@Balinus](https://discourse.julialang.org/u/Balinus)
#### Post date: [December 6, 2016, 6:49pm UTC](https://discourse.julialang.org/t/simple-metaprogramming-exercises-challenges/731/5 "2016-12-06T18:49:31Z")

</div>

Honestly, I don’t understand any examples here!

edit - By that, I mean I just can’t use these examples into Julia REPL and i feel that this thread would be super useful for beginner’s like me.

---

<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: [December 6, 2016, 6:53pm UTC](https://discourse.julialang.org/t/simple-metaprogramming-exercises-challenges/731/6 "2016-12-06T18:53:53Z")

</div>

One possible example is to generate an inlined polynomial evaluation by Horner’s method, given a variable `x` and a list of coefficients. This is actually implemented in Base (base/math.jl), but makes a good exercise because it is simple and genuinely practical:

```julia
# evaluate p[1] + x * (p[2] + x * (....)), i.e. a polynomial via Horner's rule
macro horner(x, p...)
    ex = esc(p[end])
    for i = length(p)-1:-1:1
        ex = :(muladd(t, $ex, $(esc(p[i]))))
    end
    Expr(:block, :(t = $(esc(x))), ex)
end

```

---

<div class="post-metadata">

### Author: ![mkborregaard](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkborregaard/32/556_2.png) [@mkborregaard](https://discourse.julialang.org/u/mkborregaard)
#### Post date: [December 6, 2016, 8:05pm UTC](https://discourse.julialang.org/t/simple-metaprogramming-exercises-challenges/731/7 "2016-12-06T20:05:24Z")

</div>

The way I understand @dfdx example, it is a task: implement the matchex and subs macros?

---

<div class="post-metadata">

### Author: ![JeffreySarnoff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeffreysarnoff/32/1980_2.png) [@JeffreySarnoff](https://discourse.julialang.org/u/JeffreySarnoff)
#### Post date: [December 6, 2016, 8:33pm UTC](https://discourse.julialang.org/t/simple-metaprogramming-exercises-challenges/731/8 "2016-12-06T20:33:31Z")

</div>

(imo)  
Macro contributors, Balinus and many others need an accompanying example that is easily absorbed and some words about what is happening. A second more recondite example is welcome, too.

---

<div class="post-metadata">

### Author: ![dfdx](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dfdx/32/120_2.png) [@dfdx](https://discourse.julialang.org/u/dfdx)
#### Post date: [December 6, 2016, 10:06pm UTC](https://discourse.julialang.org/t/simple-metaprogramming-exercises-challenges/731/9 "2016-12-06T22:06:27Z")

</div>

Yes, exactly. But you may also find ready-to-use solutions [here](https://github.com/dfdx/Espresso.jl/blob/master/src/core/rewrite.jl). The point of these functions as an exercise is to learn how to efficiently traverse and transform Julia expressions, which opens the doors to all kinds of fun stuff like automatic differentiation, [devectorization](https://github.com/lindahua/Devectorize.jl) or [fast math transformation](https://github.com/JuliaLang/julia/blob/master/base/fastmath.jl).

---

<div class="post-metadata">

### Author: ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)
#### Post date: [December 6, 2016, 10:45pm UTC](https://discourse.julialang.org/t/simple-metaprogramming-exercises-challenges/731/10 "2016-12-06T22:45:30Z")

</div>

I had a problem earlier today of transforming

```julia
@muladd a1*b1 + a2*b2 + a3*b3 + a4*b4

```

into a statement with `muladd` function calls:

```julia
muladd(a1,b1,muladd(a2,b2,muladd(a3,b3,a4*b4))))

```

credit for the neat solution goes to @fcard on Gitter:

```julia

macro muladd(ex)
  @assert ex.head == :call
  @assert ex.args != [:+]
  @assert ex.args[1] == :+
  esc(_muladd_meta(ex))
end

function _muladd_meta(ex)
  if length(ex.args) == 2
    return ex.args[2]
  else
    a, b = ex.args[2].args[2:end]
    rest = _muladd_meta(Expr(ex.head, :+, ex.args[3:end]...))
    return :($(Base.muladd)($a, $b, $rest))
  end
end

```

This is a good little example of a syntactic sugar macro which can be quite useful for performance.

---

<div class="post-metadata">

### Author: ![bramtayl](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bramtayl/32/3614_2.png) [@bramtayl](https://discourse.julialang.org/u/bramtayl)
#### Post date: [December 7, 2016, 1:35am UTC](https://discourse.julialang.org/t/simple-metaprogramming-exercises-challenges/731/11 "2016-12-07T01:35:44Z")

</div>

Here’s another implementation of muladd using packages to make things pretty?

```julia
using MacroTools
using ChainMap

muladd_(e) = @match e begin
    +(a_*b_) => Expr(:call, :*, a, b)
    +(a_*b_, c__) => muladd_together(a, b, c)
end

muladd_together(a, b, c) = @chain begin
    Expr(:call, :+, c...)
    muladd_
    Expr(:call, Base.muladd, a, b, _)
end

macro muladd(e)
    muladd_(e)
end

```

---

<div class="post-metadata">

### Author: ![fcard](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fcard/32/1882_2.png) [@fcard](https://discourse.julialang.org/u/fcard)
#### Post date: [December 7, 2016, 2:10am UTC](https://discourse.julialang.org/t/simple-metaprogramming-exercises-challenges/731/12 "2016-12-07T02:10:15Z")

</div>

Once again one of my macros was stricken with MacroTools… A bit of my soul dies each time. (jkjkjk!)  
Personally I prefer to use julia’s own abstractions to make things “pretty”:

```julia
macro muladd(add)
  esc(to_muladd(add))
end

function to_muladd(add)
  let mul = operands(add)[1]
    if length(operands(add)) == 1
      return mul
    else
      a, b = operands(mul)
      rest = to_muladd(:( +($(operands(add)[2:end]...)) ))
      return :($(Base.muladd)($a, $b, $rest))
    end
  end
end

operator(ex) = ex.args[1]
operands(ex) = ex.args[2:end]

```

Here is the dumb thing + error handling and tests: [https://gist.github.com/fcard/12a49827cc26a197d4d1e75481216176](https://gist.github.com/fcard/12a49827cc26a197d4d1e75481216176)  
All valid ways of doing the same thing, of course.

---

<div class="post-metadata">

### Author: ![mtsch](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mtsch/32/2072_2.png) [@mtsch](https://discourse.julialang.org/u/mtsch)
#### Post date: [December 7, 2016, 7:43am UTC](https://discourse.julialang.org/t/simple-metaprogramming-exercises-challenges/731/13 "2016-12-07T07:43:58Z")

</div>

For a simple, but fun exercise, try writing a macro that turns expressions into anonymous functions, using `_` as arguments. An example of the macro being used would be:

```julia
map(@par(_ * max(_, 2)), 1:4, 4:-1:1)

# 4 6 6 8

```

Another thing you could try is adding an option of labeling the `_` arguments with numbers, making `_1` the first argument, `_2` the second and so on. You could also add type annotations.

---

<div class="post-metadata">

### Author: ![MikeInnes](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mikeinnes/32/3656_2.png) [@MikeInnes](https://discourse.julialang.org/u/MikeInnes)
#### Post date: [December 7, 2016, 11:24am UTC](https://discourse.julialang.org/t/simple-metaprogramming-exercises-challenges/731/14 "2016-12-07T11:24:32Z")

</div>

Well hey, if we’re macro-golfing:

```julia
macro muladd(ex)
  foldr((a, b) -> :(muladd($(a.args[2:end]...), $b)), ex.args[2:end])
end

```

As another starting out idea, here’s the simplest thing I can think of that isn’t equivalent to a closure:

```julia
(a, b) = (1, 2)
@swap a b
(a, b) == (2, 1)

```

Should be pretty easy for a beginner to write.

---

<div class="post-metadata">

### Author: ![MikeInnes](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mikeinnes/32/3656_2.png) [@MikeInnes](https://discourse.julialang.org/u/MikeInnes)
#### Post date: [December 7, 2016, 12:36pm UTC](https://discourse.julialang.org/t/simple-metaprogramming-exercises-challenges/731/15 "2016-12-07T12:36:07Z")

</div>

Here’s a harder variation on the muladd challenge: Make it general enough that it can look at any code and transform the inner muladds, keeping everything else the same. Here’s a version using MacroTools; consider me very impressed if anyone can make it cleaner without 🙂

```julia
macro muladd(ex)
  MacroTools.prewalk(ex) do ex
    @capture(ex, +(x_ * y_, cs__)) || return ex
    :(Base.muladd($x, $y, $(foldl((a,b)->:($b+$a), cs))))
  end |> esc
end

a = a1*b1 + a2*b2 + a3*b3
b = a4*b4 + f(a*b + c)
# becomes
a = muladd(a1,b1,muladd(a3,b3,a2 * b2))
b = muladd(a4,b4,f(muladd(a,b,c)))

```

---

<div class="post-metadata">

### Author: ![fcard](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fcard/32/1882_2.png) [@fcard](https://discourse.julialang.org/u/fcard)
#### Post date: [December 7, 2016, 3:05pm UTC](https://discourse.julialang.org/t/simple-metaprogramming-exercises-challenges/731/16 "2016-12-07T15:05:25Z")

</div>

```julia
macro muladd(ex)
  esc(to_muladd(ex))
end

function to_muladd(ex)
  is_add_operation(ex) || return ex
  operands = collect(zip(
    to_muladd.((x->x.args[2]).(ex.args[2:end])), 
    to_muladd.((x->x.args[3]).(ex.args[2:end]))))
    
  last_operation = :($(operands[end][1]) * $(operands[end][2]))
            
  foldr(last_operation, operands[1:end-1]) do xs, r
    :($(Base.muladd)($(xs[1]), $(xs[2]), $r))
  end
end
is_add_operation(ex::Expr) = ex.head == :call && !isempty(ex.args) && ex.args[1] == :+
is_add_operation(ex) = false

```

?  
Of couse I could make this more compact, but I don’t think code golf was ever the point of this. It’s not about the golf, Mike, it’s about the _love_! (I don’t know what that means)  
Nice one with the `foldl` tho, I keep missing the opportunities to use that 😛

* * *

**Edit** : I added this new functionality to the gist of my no-fun version , which I still like despite the hardships we encountered together.  
**Edit2** : It has dawned on me that we may have gone off topic a bit, I will see if I can come up with a few simple macros to make up for it.

* * *

> Mike Innes really is the He-Man to my Skeletor, I keep trying to take over ~~Eternia~~ Julia by introducing my evil verbosity and taking away all the fun, but he keeps foiling my dastardly plans through the power of ~~Grayskull~~ CodeGolfing.

---

<div class="post-metadata">

### Author: ![mkborregaard](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkborregaard/32/556_2.png) [@mkborregaard](https://discourse.julialang.org/u/mkborregaard)
#### Post date: [March 7, 2017, 4:19pm UTC](https://discourse.julialang.org/t/simple-metaprogramming-exercises-challenges/731/17 "2017-03-07T16:19:30Z")

</div>

> [@stevengj](#):
>
> ```julia
> macro horner(x, p...)
> ex = esc(p[end])
> for i = length(p)-1:-1:1
> ex = :(muladd(t, $ex, $(esc(p[i]))))
> end
> Expr(:block, :(t = $(esc(x))), ex)
> end
> 
> ```

This is really a great example, because of the cool ways it uses interpolations and escaping. It could be really useful for macro learners, I think, with a line-by-line description of the construction and considerations.

---

<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: [January 6, 2018, 3:18pm UTC](https://discourse.julialang.org/t/simple-metaprogramming-exercises-challenges/731/18 "2018-01-06T15:18:40Z")

</div>

Transform a vector of symbols into a symbol of tuples:  
`tuplify([:a,:b]) == :((a,b))`

My solution works, but it feels a bit kludgy:

```julia
function tuplify(x)
    a = Expr(:tuple, x)
    a.args = x
    a
end

```

---

<div class="post-metadata">

### Author: ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)
#### Post date: [January 6, 2018, 3:53pm UTC](https://discourse.julialang.org/t/simple-metaprogramming-exercises-challenges/731/19 "2018-01-06T15:53:34Z")

</div>

```julia
julia> t = [:a, :b];

julia> :(($(t...),))
:((a, b))

```

---

<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: [January 6, 2018, 3:54pm UTC](https://discourse.julialang.org/t/simple-metaprogramming-exercises-challenges/731/20 "2018-01-06T15:54:28Z")

</div>

> [@Tamas\_Papp](#):
>
> julia\> :(($(t…),))  
> :((a, b))

Oh that’s much better, thanks!

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