The following exercises request the development of a range of syntactic Racket extensions. Some of these already exist under a different name; don’t just compile the new surface syntax to those but develop your own translation. (If you think a feature is better off implemented as a run-time function, do so.)
Please make sure to solve the first and the last exercise; of the remaining, solve as many as you can. Remember to work in pairs.
Exercise 1. Modify define-world* so that it binds each given identifier to its place in the sequence. We start counting at 0 so that
(define-world* x y z)binds x to 0, y to 1, and so on.
Consider two variants: one that compiles the values at compile time and another one that computes them at run time. The second one might be a bit easier, but do try your hands at both.
Expression = ... | (loop Variable0 ((Variable1 Expression1) ...) Expression0 ...)
The extension maps the surface syntax to 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.
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.
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.ExampleFor (f 'x), x shows up in both regular clauses, while for (f 'a) a does not show up at all.