Metaprogramming Elixir: think about quote and unquote from viewpoint of context

September 11, 2017    Elixir


  • macOS sierra
  • Erlang/OTP 20 [erts-9.0] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]
  • Elixir 1.5.1

What is this article about?

I ganna write about behavior of quote and unquote from viewpoint of context.

I thought quote and unquote both have to be used toghether when I started to learn metaprogramming. But chapter of code generation in Metaprogramming Elixir book showed me some weird examples.

One of them is like this.

mimes.exs defines several functions based on type and extension in mimes.txt.

this code works like this. When we set a type, a function returns extensions. On the other hand a function returns type when we set a extension.

Here this unquote is called “unquote fragments”.

This made me curious to search role of exceptional macro more. So I understood why this code works well without quote after I run a little test codes.

Thinking relation between unquote and context reveals what unquote does precisely and then it leads to think relation between quote and context.

I believe once we got these relationship, it helps we use macro more.

Let’s check these macro simply

As you know the role of quote normally translates expression to AST tuple except 5 literals.

Thanks to quote, we can manipulate AST freely. And unquote is needed when we inject variables to AST.

Yes. The variable: second is evaluated within AST. Role of unquote is resolving whether a name of variable binds a value or not.

But from where…?

Role of unquote is resolving whether a name of variable binds a value or not by referring to variables in a high context.

Here I wanna bring up context which is called scope in different languages. Before we consider unquote, let’s just check variables context with def and defmacro

First I set the value at the outside of def and defmacro.

c1 takes an augment named a then check what’s bound, c2 try to check b, and c3 bind an augment to b then check it.

*c2 fails because of compile error.

Now we can see context is marked off by a def and defmacro you know. variables never refer to outside variables in the body of these macros.

Let’s check other example. I added unquote(a) in c1 and change c2 function.

This example leads to what unquote does right?

Unquote obviously refer to a high context

Both function show a outside value even if function has same name of variable.

And one more thing I gave a function a variable which binds atom by using unquote.

It shows

This example show us where area belong to function context.

Think about def NAME, do: BODY. NAME and BODY both are in a function context.

Now we can explain why first mimes.exs works well.

type and extensions currently bind a value at the outside of exts_from_type and type_from_ext context

That’s why unquote is used in order to define function like following

Unquote fragments and unquote both just acts upon context and resolving

Let’s think how Mime module allow arbitrary modules to use Mime by __ using __

This code is likely to work well, isn’t it? This is because mimes.exs generates new codes without defmacro and quote.

Oh you are right. It can’t work because defmacro is designed to take AST as arguments and return new AST.

But… This code fails because of some reasons

Type is not defined at line 8.

In the def and defmacro a key word def is not evaluated so if we use unquote here, unquote refer to the outside of defmacro __using__

OK. Let’s try remove unquote. And compile result is… Another error. We can’t invoke it inside function/macro.

Hmmmmmm, how do we do that? Is there any marker except def and defmacro?

Yes. Just remember such examples. unquote refer to second over quote and as you know quote can be put in anywhere!

Put quote on and get back unquote!

Good! really good. Quote actually mark off context as well


How was that? Considering context of unquote and quote together, it can be easy to read what is going on metaprogramming code I guess


  • unquote is resolving whether a name of variable binds a value or not by referring to variables in a high context.
  • quote mark off context as well as treating expressions as an AST

Actually quote have some extra informations about context, but I recommend that you read Metaprogramming Elixir book for it.

Thank you for reading That’s all :)

Let’s enjoy Elixir!!

comments powered by Disqus