# Introduce bindings for macro user

I'm doing the Racket track on exercism.io and solved the grains exercise:

Write a program that calculates the number of grains of wheat on a chessboard given that the number on each square doubles.

(test cases etc on exercism)

So I wrote a straightforward recursive solution:

#lang racket

(provide square total)

(define (square n)
(cond
[(n . = . 1)    1]
[(n . > . 1)    (* 2 (square (- n 1)))]
[else           (error "invalid number:" n)]))

(define (sum n)
(cond
[(n . = . 1)    1]
[(n . > . 1)    (+ (square n) (sum (- n 1)))]
[else           (error "invalid number:" n)]))

(define (total)
(sum 64))


Then I went to clean it up by factoring out the induction:

#lang racket

(provide square total)

(define-syntax (induction stx)
(syntax-case stx ()
((induction base rule)
(with-syntax ((n (datum->syntax stx 'n)))
#'(lambda (n)
(cond
((n . = . 1)   base)
((n . > . 1)   rule)
(else          (error "invalid number:" n))))))))

(define square  (induction 1 (* 2 (square (- n 1)))))
(define sum     (induction 1 (+ (square n) (sum (- n 1)))))

(define (total)
(sum 64))


I got a couple of questions:

1) Is that the most straightforward way to introduce a new binding for the macro user?

Like, this is quite wordy. I guess I could wrap the "with-syntax" part into another macro, 'cause right now this feels very "built out of raw plumbing" to me.

It's also annoying that "define-syntax-rule" doesn't give me "stx", so I don't see a way to introduce new bindings. I'd like to write something like:

(define-syntax-rule (induction base rule)
(syntax-let ((n))
(lambda (n)
(cond
((n . = . 1)    base)
((n . > . 1)    rule)
(else           (error "invalid number:"))))))


Is there anything built-in for that?

2) For argument clarity, I'd like to write it more like this:

(define (square n)
(induction 1 (* 2 (square (- n 1)))))


How'd I do that? Like, I'd... have to capture the "n" argument correctly (how?), and return, uh... the body of the lambda? I'm confused.

When writing macros, it is best to avoid using functions like datum->syntax to conjure up identifiers. Instead, your macro should take the identifiers to bind from the macro use site.

For your example, I would write it like this:

#lang racket

(provide square total)

;; note how n is passed in as an argument
(define-syntax-rule (induction n base rule)
(lambda (n)
(cond [(n . = . 1) base]
[(n . > . 1) rule]
[else        (error "invalid number:" n)])))

(define square (induction n 1 (* 2 (square (- n 1)))))
(define sum    (induction n 1 (+ (square n) (sum (- n 1)))))

(define (total)
(sum 64))


Macros written in this style are more composable and cooperate with macro hygiene. Racket's macro system lets you break this hygiene in a controlled way, but that is usually a bad idea.

Also, for a simple program like this I would usually not bother writing a macro. In this case, you could even have abstracted this using only first-class functions instead of macros.

You may also wish to read Macros and Languages in Racket and Fear of Macros if you haven't already.