Hacker News new | ask | show | jobs
by davexunit 3387 days ago
>Could you please give an example of why you'd want to change your source code programatically?

To create new syntax and be your own language designer. This is what macro systems allow for. Here's a very contrived and simple example. Guile comes with no equivalent of the `++` operator that we know from C, C++, etc. So in the event that we have some imperative code that is mutating a counter, we'd have to write something like this:

    (define counter 0)
    ;; do some stuff...
    (set! counter (+ counter 1))
Quite a lot more typing! It would be especially annoying if we had many such counters. Normally, when we want to factorize code, we'd write a function, but there's a problem: We can't write a function that mutates any given variable. So, this wouldn't work:

    (define (++ n) (set! n (+ n 1)))
    (define counter 0)
    (++ counter)
This is just mutating a local variable `n`, nothing happens to the variable `counter`, it's still 0. So what do we do? Instead of a function abstraction, we'll use a syntactic abstraction instead. Here is a macro that does what we want:

    (define-syntax-rule (++ var) (set! var (+ var 1)))
    (define counter-a 0)
    (define counter-b 0)
    (++ counter-a)
    (++ counter-b)
    (++ counter-a)
Now `counter-a` is 2 and `counter-b` is 1. The `++` macro is a program that writes programs. It takes `(++ counter-a)` and expands it into the code `(set! counter-a (+ counter-a 1))`.

The reason these syntactic abstractions are so easy to make is because of the homoiconic Lisp syntax. I hope this has made sense and is helpful. Moving on from this simple example, we can create entirely new languages that are embedded in Scheme if we wanted to, adding things that are too specific to a problem domain to ever be in the standard language's syntax but very useful for the problem we are trying to solve.

1 comments

Is the last line in your failed function example supposed to read:

    (++ counter)

?
Yup, sorry. Fixed.