< B / >

Macros

Code that writes Code (so AI, basically)
Started Last edited

The idea is pretty simple:

We write code, and sometimes we repeat ourselves there. So why not write code that abstracts over this repetition?

That is what Macros are.

§ C Macros

The lowest sophistication level (and the worst to work with) is something like C preprocessor macros. There, you do the easiest thing possible: A string replacement over the full following program text, irrespective of anything else.

So a Macro in C has this type signature:

CMacro :: String -> String

simple.c
#define LALA "hohohoho"
char laugh[] = LALA

->

simple.c
char laugh[] = "hohohoho"

A standard C Macro usage looks like this:

min.c
#define min(X, Y) ((X) < (Y) ? (X) : (Y))
x = min(a, b); → x = ((a) < (b) ? (a) : (b));
y = min(1, 2); → y = ((1) < (2) ? (1) : (2));
z = min(a + 28, *p); → z = ((a + 28) < (*p) ? (a + 28) : (*p));

But since this is just doing straight string replacement, anything can happen (There’s just no rules whatsoever for the expansion, so you can have unbalanced parentheses and other weird stuff).

They’re still powerful, and you probably want to use them in C, but we can do better.

§ Lisp Macros

Lisp Macros do better: They’re not doing string replacement, but operate on the syntax tree.

LispMacro :: Syntax -> Syntax

The also have a second pretty helpful property: They use the same syntax as the base language. So their type is actually this:

LispMacro :: LispSyntax -> LispSyntax

This is what they look like:

> (defmacro the-macro (a b)
`(+ ,a (* ,b 3)))
> (the-macro 4 5) ;; => 19

This makes them way more generally useful (for example)

But they, too, have a problem: They’re not hygienic.

That is, they’re introducing variables into their target program that could be referenced both from the inside and outside.

This possibly couples the macro source code to the location it’s being used in, which, if you squint, is the one unambigiously bad (default) feature in programming languages (again): Dynamic Scoping

There’s an easy fix for this, however: gensym

But this makes for a relatively bad default, and we shouldn’t rely on programmers knowing all the ways in which they could fuck up, and then having the mental workload left to fix them.

Draft in Progress

Writing in here is haphazardous, disjointed and sketchy.

It's probably a good idea to come back later.

§ Scheme Macros

Scheme was the first language that didn’t have the problem of accidental scope leaking. They introduced hygienic macros.

§ Racket Macros

Racket escalates this completely, and has facilities to define whole new languages.

§ Notes