;;; while-for.rkt
;;; Definition des macros while et for en Scheme

#lang racket

(provide while for)   ; mon for, pas celui de Racket (voir en bas de page) !

(define-syntax while
  (syntax-rules ()
    ((while test e1 e2 ...) (do () ((not test) (void)) e1 e2 ...))))

(define-syntax for
  (syntax-rules (from to by in)
    ((for i from a to b by c e1 e2 ...) (let ((vb b) (vc c))
                                          (do ((i a (+ i vc)))
                                            ((> i vb) (void))
                                            e1 e2 ...)))
    ((for i from a to b e1 e2 ...) (for i from a to b by 1 e1 e2 ...))
    ((for x in L e1 e2 ...) (for-each (lambda (x) e1 e2 ...) L))))

;(define (test-while-for)
;  (let ((x 1))
;    (while (< x 10) 
;      (write x) (display " ") (set! x (+ x 1)))
;    (newline)
;    (for x from 1 to 10 
;      (write x) (display " "))
;    (newline)
;    (for x from 1 to 10 by 2 
;      (write x) (display " "))
;    (newline)
;    (for x in '(a b c d)
;      (write x) (display " "))))
;    
;(test-while-for)

; ------------------- le vrai 'for' de Racket ------------------------------------

; En realite, cette forme (for i from a to b by c e ...) a ete integre au cours
; pour des raisons purement pedagogiques, afin d'illustrer une macro interessante.
; Mais Racket a pris depuis quelques annees les boucles 'for' de Python en les
; adaptant au monde Lisp (ce n'est pas pour rien qu'il se nomme 'Racket'...).
; Il y a plusieurs formes de boucles for, adaptees aux nombres, aux listes,
; aux vecteurs, aux tables de hash-code, etc. On peut meme se construire les
; siennes avec une macro. En voici seulement deux exemples :
;
;(define (somme a b)                            ; def somme(a,b) :
;  (for/sum ([i (in-range a (+ b 1))]) i))      ;     return sum(i for i in range(a,b+1))
;
;(define (produit a b)                          ; def produit(a,b) :
;  (for/product ([i (in-range a (+ b 1))]) i))  ;     return --- en Python ils n'aiment pas les produits ? ---
;
;(define ($map f L)
;  (for/list ([x (in-list L)]) (f x)))
;
;; attention, j'utilise ici le vrai 'for' de Racket et non celui defini plus haut !
;
;(define-syntax forever
;  (syntax-rules ()
;    ((forever e ...) (for ([i (in-naturals)]) e ...))))    ;   je m'amuse  :-)
;
;(define-syntax while
;  (syntax-rules ()
;    ((while test e ...) (forever #:break (not test) e ...))))
;
; etc.
