Power of syntax-rules ... ========================= A common idiom is to define a recursive helper and call it right away: (letrec ((w (lambda () (if (begin ... (w)))))) (w)) Scheme's let has a form for this, referred to as named let. Let's see it used for a recursive helper (i.e. fold-in) sum-of-squares: (define (sum-of-squares n) (let s-o-s ((s 0) (i 1)) ; s-o-s procedure of two arguments s and i ; called initially with 0 and 1 (if (> i n) s (s-o-s (+ s (* i i)) (+ i 1))))) This is short for: (define (sum-of-squares n) (letrec ((s-o-s (lambda (s i) (if (> i n) s (s-o-s (+ s (* i i)) (+ i 1)))))) (s-o-s 0 1))) Let's see how we could define named-let ourselves to do this: (define-syntax named-let (syntax-rules () ((named-let (( ) ...) ...) (letrec (( (lambda ( ...) ; puts one of each here ...))) ( ...))))) ; puts one of each here Notice that in the code the variables and initial values are together, but the ... can loop over them individually. Assignment 3 has an example (class) with nested .... Recursion in syntax-rules ========================= Let's write a version of match that: doesn't require () around each clause defaults to returning the original value if there's no match So we want to be able to write: (define (push-negations p) (match-transform p ('not ('not q)) (push-negations q) ('not (p1 'or p2)) (push-negations `((not ,p1) and (not ,p2))) ('not (p1 'and p2)) (push-negations `((not ,p1) or (not ,p2))) (p1 op p2) `(,(push-negations p1) ,op ,(push-negations p2)))) Here is match-transform: (define-syntax match-transform (syntax-rules () ((_ ) ) ; repeating the name of the syntactic form is redundant ; so syntax-rules allows _ instead as shorthand ((_ ...) (match ( ) (e (match-transform e ...)))))) It will rewrite (match-transform p ('not ('not q)) (push-negations q) ('not (p1 'or p2)) (push-negations `((not ,p1) and (not ,p2))) ('not (p1 'and p2)) (push-negations `((not ,p1) or (not ,p2))) (p1 op p2) `(,(push-negations p1) ,op ,(push-negations p2))) into (match p (('not ('not q)) (push-negations q)) (e (match-transform e ('not (p1 'or p2)) (push-negations `((not ,p1) and (not ,p2))) ('not (p1 'and p2)) (push-negations `((not ,p1) or (not ,p2))) (p1 op p2) `(,(push-negations p1) ,op ,(push-negations p2))))) and continue, eventually getting down to (match p (('not ('not q)) (push-negations q)) (e (match e (('not (p1 'or p2)) (push-negations `((not ,p1) and (not ,p2)))) (e (match e (('not (p1 'and p2)) (push-negations `((not ,p1) or (not ,p2)))) (e (match e ((p1 op p2) `(,(push-negations p1) ,op ,(push-negations p2))) (e e))))))))