M4 Macros
January 30, 2015
I decided to write a macro to factor integers. I first wrote this Scheme code, as a model for what I wanted to do; the algorithm is simple trial division:
> (define (fact n d)
(if (< n (* d d))
(list n)
(if (zero? (modulo n d))
(cons d (fact (/ n d) d))
(fact n (+ d 1)))))
> (define (factors n) (fact n 2))
> (factors 32)
(2 2 2 2 2)
> (factors 35)
(5 7)
> (factors 87463)
(149 587)
> (factors 13290059)
(3119 4261)
Then I rewrote in m4; the only hard part was getting the quoting right:
$ m4
define(fact,
`ifelse(eval($1 < $2 * $2), 1, $1,
`ifelse(eval($1 % $2 == 0), 1,
$2 fact(eval($1 / $2), $2),
fact($1, incr($2)))')')dnl
define(factors, `fact($1, 2)')dnl
factors(32)
2 2 2 2 2
factors(35)
5 7
factors(87463)
149 587
factors(13290059)
3119 4261
That’s not exactly transparent, though I suppose if you write enough m4 code you’ll get accustomed to it. Most uses of m4 are simple substitution, for which it is highly suitable.
You can run the Scheme code at http://programmingpraxis.codepad.org/hAf1OFnz; no m4 processor is available.
And a paper from computational dreamtime (well, 1965 anyway), describing Strachey’s GPM, the original ancestor of m4:
Click to access 225.full.pdf