7.4.0.4

6 Lab Syntax Patterns & Classes

Jay McCarthy

Exercise 10. Add syntax class annotations to your define&provide macro. Write test cases to demonstrate the bad behavior you are protecting against.

Exercise 11. Add syntax class annotations to your simple-for/fold macro. Write test cases to demonstrate the bad behavior you are protecting against.

Exercise 12. Add syntax class annotations to your condd macro. Write test cases to demonstrate the bad behavior you are protecting against.

Exercise 13. Define a syntax class that identifies valid formals for a lambda. You can test it with the macro

(define-simple-macro (my-lambda fs:my-formals body:expr ...+)
  (lambda fs body ...))

But, all invalid forms should be an error in my-lambda, not an error in lambda.

Start by handling only normal arguments, then support rest arguments, then add default arguments, finally add keyword arguments. If this was too easy, extend your class to properly error when the same keyword is used multiple times, as well as erroring if the same identifier is used multiple times.

Exercise 14. Add support for the [question => answer-function] form of cond to your condd macro by designing a syntax class and using it. We recommend defining separate condd-test-clause and condd-define-clause syntax classes, rather than trying to normalize these two different kinds of clauses.

Exercise 15. Write a syntax class called match-pattern that allows this macro:

(define-simple-macro
  (simple-match-define mp:match-pattern scrutinee:expr)
  (define-values (mp.x ...)
    (mp.matcher
     scrutinee
     (λ () (error 'simple-match-define "Match does not apply!")))))
 
(define (user s)
  (simple-match-define
   (#:cons (#:or (#:number x) (#:boolean x))
    (#:cons (#:number y)
     (#:or (#:null z) (#:boolean z))))
   s)
  (if (number? x) (+ x y)
      (if x y z)))
 
(user (cons 1 (cons 2 empty)))
; => 3
 
(user (cons #t (cons 2 empty)))
; => 2
 
(user (cons #t (cons 2 #f)))
; => 2
 
(user (cons #t (cons 2 #t)))
; => 2
 
(user (cons #f (cons 2 #t)))
; => #t
 
(user (cons #f (cons 2 #f)))
; => #f

Your match-pattern class will support five different variants: #:cons, #:or, #:number, #:boolean, and #:null. The #:cons and #:or variants will be recursive.

The matcher attribute should be the syntax of a function that accepts a value and a function to call if it does not match. The return values should be the matched values.