Exercice 1. Soit le code ci-dessous qui définit la macro "match" : ;;;---------------------------------------------------------------------------- ;; Macros pour faire des évaluations pendant la phase d'expansion de ;; macro, et la phase d'exécution. (define-macro (for-macro-expansion . body) (eval `(begin ,@body)) #f) (define-macro (for-macro-expansion-and-execution . body) `(begin (for-macro-expansion ,@body) ,@body)) ;;;---------------------------------------------------------------------------- ;; La macro "match". (for-macro-expansion-and-execution (define-macro (match sujet . clauses) (define (if-equal? var gab oui non) (cond ((and (pair? gab) (eq? (car gab) 'unquote) (pair? (cdr gab)) (null? (cddr gab))) `(let ((,(cadr gab) ,var)) ,oui)) ((null? gab) `(if (null? ,var) ,oui ,non)) ((symbol? gab) `(if (eq? ,var ',gab) ,oui ,non)) ((or (boolean? gab) (char? gab)) `(if (eq? ,var ,gab) ,oui ,non)) ((number? gab) `(if (eqv? ,var ,gab) ,oui ,non)) ((pair? gab) (let ((carvar (gensym)) (cdrvar (gensym))) `(if (pair? ,var) (let ((,carvar (car ,var))) ,(if-equal? carvar (car gab) `(let ((,cdrvar (cdr ,var))) ,(if-equal? cdrvar (cdr gab) oui non)) non)) ,non))) (else (error "unknown pattern")))) (let* ((var (gensym)) (fns (map (lambda (x) (gensym)) clauses)) (err (gensym))) `(let ((,var ,sujet)) ,@(map (lambda (fn1 fn2 clause) `(define (,fn1) ,(if-equal? var (car clause) (if (and (eq? (cadr clause) 'when) (pair? (cddr clause))) `(if ,(caddr clause) ,(cadddr clause) (,fn2)) (cadr clause)) `(,fn2)))) fns (append (cdr fns) (list err)) clauses) (define (,err) (error "match failed")) (,(car fns))))) (define gensym ;; une version de gensym utile pour le deboguage (let ((count 0)) (lambda () (set! count (+ count 1)) (string->symbol (string-append "g" (number->string count)))))) ) ;;;---------------------------------------------------------------------------- Expliquez à quoi sert l'appel de macro "for-macro-expansion-and-execution" autour de la définition de la macro match. À l'aide de la macro match, définissez une macro "for" qui permet d'écrire des boucles avec la syntaxe suivante : (for i = 1 to 5 do (for j = i to (* i i) do (pp (list i j)))) Votre macro doit refuser les utilisations de for qui n'ont pas le "=", "to" et "do" aux bons endroits. Exercice 2. Voici le code pour un expanseur de forme spéciale pour un sous-ensemble des formes spéciales de Scheme : ;;;---------------------------------------------------------------------------- (define (expand expr) (match expr (,c when (constant? c) c) (,v when (symbol? v) v) ((quote ,x) `(quote ,x)) ((set! ,v ,E1) `(set! ,v ,(expand E1))) ((set! . ,rest) (error "improper set!")) ((define (,v . ,params) . ,Es) `(define ,v ,(expand `(lambda ,params ,@Es)))) ((define ,v ,E1) `(define ,v ,(expand E1))) ((define . ,rest) (error "improper define")) ((if ,E1 ,E2) `(if ,(expand E1) ,(expand E2) #f)) ((if ,E1 ,E2 ,E3) `(if ,(expand E1) ,(expand E2) ,(expand E3))) ((if . ,rest) (error "improper if")) ((begin ,E1) (expand E1)) ((begin ,E1 . ,Es) (expand (let ((v (gensym))) `(let ((,v ,E1)) (begin ,@Es))))) ((begin . ,Es) (error "improper begin")) ((lambda ,params . ,Es) `(lambda ,params ,(expand `(begin ,@Es)))) ((lambda . ,rest) (error "improper lambda")) ((,E0 . ,Es) (map expand (cons E0 Es))) (,_ (error "unknown expression" expr)))) (define (constant? c) (match c ((quote ,x) #t) (,x (or (number? x) (string? x) (boolean? x) (char? x))))) ;;;---------------------------------------------------------------------------- ;; Tests : (pp (expand '(let ((x 1)) x))) (pp (expand '(begin A B C))) (pp (expand '(lambda (x) A B C))) ;;;---------------------------------------------------------------------------- Vous devez étendre la fonction "expand" pour traiter les formes spéciales "let", "let*", "letrec", "and", et "or". Le code généré par la fonction "expand" peut contenir des variables, des constantes, des appels de fonction, ainsi que des formes spéciales. Énumérez toutes les formes spéciales qui peuvent apparaître dans le code généré par la fonction "expand". Exercice 3. Soit la définition de macro suivante : (define-macro (define-macro* pattern . body) `(define-macro ,pattern (let ((result (begin ,@body))) (pretty-print (list (list ',(car pattern) ,@(cdr pattern)) '--> result)) result))) À quoi peut servir la macro "define-macro*"?