# The self-hosting \`derive\` macro

**URL:** <https://racket.discourse.group/t/the-self-hosting-derive-macro/1116>\
**Category:** Show & Tell\
**Created:** [July 1, 2022, 7:22pm UTC](https://racket.discourse.group/t/the-self-hosting-derive-macro/1116 "2022-07-01T19:22:04Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![slg](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/slg/32/528_2.png) [@slg](https://racket.discourse.group/u/slg)\
**Post date:** [July 1, 2022, 7:22pm UTC](https://racket.discourse.group/t/the-self-hosting-derive-macro/1116/1 "2022-07-01T19:22:04Z")

</div>

I came up with a `derive` macro that specializes `match` as a refactoring tool for self-hosted programs. I built it on top of [blossoms](https://racket.discourse.group/t/self-hosting-racket-base-programs-with-blossoms/980)

I think it's fun to use because any position in expression context can reflect on its role in another expression, using all values available at runtime. Source code to be published in new Denxi edition I hope to have out by the end of the month.

For now, I'll just go over the current syntax and behavior of the macro.

```scheme
(module+ test
  (derive derivative
          #:as (declassify derivative)
          #:taxa rule-position
          #:diff
          [`(derive derivative ,_ ... #:diff [,datum ,_] ,_ ...)
           (rule-position datum)]
          [(list-no-order (? rule-position? rp) _ ...)
           rp]))

```

A `derive` call expresses all the s-exp level edits you'd like to make to the surrounding program if your text editor's cursor sat at _the corresponding call site_. This specific example is kind of neat because the first `match` pattern under `#:diff` is targeting itself. The result of the expression is the datum form of that pattern.

```scheme
(quote (quasiquote (derive derivative
                           (unquote _) ...
                           #:diff
                           [(unquote datum) (unquote _)]
                           (unquote _) ...)))

```

In general, `(derive ...)` is a copy of the entire surrounding source code as a list, refactored using a front-end to `match`. The match clauses under `#:diff` control what code is replaced with new values. The clauses match elements provided in child-to-parent order, such that the `(derive ...)` expression itself is the first expression used in `match`. Next, it's the `(module+ test ...)`, then any hypothetical traversal of proper or improper lists leading to the topmost enclosing S-expression. If no clauses match for an element at some level, then that element stays. All uses of `match` occur during runtime. The `derive` macro only serves to associate the call site with the runtime behavior.

Every element of an (im)proper list has its own child-to-parent traversal, so it is possible to distinguish `equal?` values (like copies of `module` forms) based on these traversals. This is a nice property, because it means that any lexically-equal `derive` starts operating _exactly on itself_. This bleeds over into other benefits, like `module` forms containing programs that can recognize their position in the whole module tree.

Finally, the `derivative`, `#:as (declassify derivative)`, and `#:taxa` are all related. The first `derivative` identifier binds the result of the final use of `match`. The expression after `#:as` uses that binding to compute the value of the whole `derive` macro, kind of like how `#:result` works in `for/fold`. The `declassify` function is an accessor that returns the value encapsulated by the ad-hoc `#:taxa` (we don't want a `rule-position` classifier, we want the classified value). The `#:taxa` identifiers help generate temporary constructors and predicates that classify values without ambiguity in match patterns.

This example works by having a `match` pattern extract the datum form of itself to classify accordingly. Since I'm traversing towards parent values, the `list-no-order` rule naturally propagates classified elements. `#:as` returns the element itself, without the classifying wrapper. In effect, this replaces the whole program's source code with just that one `match` pattern.
