7.0.0.13

3 — Racket Syntax Extensions

Due Tuesday, 30 Jan; 9:00am

Delivery Send me a Racket file name 3-lastname1-lastname2.rkt with your solutions. The file should start as follows:
; Problem Set 3
; Lastname1, Firstname1
; Lastname2, Firstname2
Separate the various problems from each other with a comment line of 99 dashes.

image

Develop the syntax transformations in Racket:

  • loop, which has the following grammar:
      Expression = ...
      | (loop Variable0 ((Variable1 Expression1) ...) Expression0 ...)
    It creates a recursive function, named Variable0, whose parameters are Variable1 ..., whose body is Expression0 ..., and immediately applies it to the arguments Expression1 .... The Variable0 function is not visible outside of the loop expression.

  • all, which has the following grammar:
      Expression = ...
      | (all Expression ...)
    If all of the expressions evaluate to a non-#false value, all produces the list of the results; otherwise it produces #false.

  • dispatch, which has this grammar:
      Expression = ...
      | (dispatch Expression DClause ...)
      | (dispatch Expression DClause ... [orelse Expression])
         
      DClause = [(Identifier ...) Expression]
    It evaluates the first Expression to a symbol; if it produces anything else, dispatch raises an error. Next dispatch checks whether the symbol occurs in any of the identifier lists (interpreted as list of symbols) and evaluates all corresponding expressions. If the symbol does not show up in any of the identifier lists and an orelse clause is present, the expression in that clause is evaluated.

    Example
    (define (f x)
      (dispatch x
                [(x y) (displayln 0)]
                [(z x) (displayln 1)]
                [orelse (displayln 2)]))
    For (f 'x), x shows up in both regular clauses, while for (f 'a) a does not show up at all.

  • struct/con, which has this grammar:
      Expression = ...
      | (struct/con Identifier ({Identifier : Identifier} ...))
    The difference to plain struct is that each field comes with a second identifier, to the right of :. This identifier names a predicate.

    The form creates a struct type definition whose constructor ensures that the respective field values satisfy the named predicate.

    Note Racket’s struct comes with guards. The point of this exercise is that you may use struct but not its guard feature. Instead, override the struct constructor. See hints.

    Hint (1) It is possible to set! a function name. (2) Use begin to splice a sequence of code into a context.

  • define-rewrite-rule, which accepts a syntax pattern and a syntax template and then synthesizes an appropriate combination of define-syntax and syntax-parse.

    Example

    (define-rewrite-rule
      (loop-for-ever exp)
      ; >
      (local ((define (for-ever) (begin exp (for-ever)))) (for-ever)))
If you think a feature is better off implemented as a function, do so.