;; For loops for integer ranges and lists. (1.01)
(use-modules (srfi srfi-1))
(define-syntax for
(syntax-rules (in .. .= by)
;; Integer range exclusive by step.
((for index in start .. end by step body ...)
(let* ((count (max (ceiling-quotient (- end start) step) 0))
(final (+ start (* count step))))
(do ((index start (+ index step)))
((= index final))
body ...)))
;; Integer range inclusive by step.
((for index in start .= end by step body ...)
(for index in start .. ((if (negative? step) - +) end 1) by step
body ...))
;; Integer range exclusive default step.
((for index in start .. end body ...)
(for index in start .. end by 1
body ...))
;; Integer range inclusive default step.
((for index in start .= end body ...)
(for index in start .= end by 1
body ...))
;; Iterate over a list.
((for item in list body ...)
(for-each (lambda (item)
body ...)
list))))
;; Main.
(define (print-range start end step)
(for i in start .. end by step
(format #t "~A " i))
(newline)
(for i in start .= end by step
(format #t "~A " i))
(newline)
(let ((n (max (ceiling-quotient (- end start) step) 0)))
(for i in (iota n start step)
(format #t "~A " i)))
(newline))
(print-range 1 5 1)
(print-range 1 11 2)
(print-range -11 -1 2)
(print-range 5 1 -1)
(print-range 11 1 -2)
(print-range -1 -11 -2)
;; Nested default step.
(define (pythagorean-triples n)
(define (primitive-pythagorean-triple? x y z)
(and (< x y z)
(= (+ (* x x) (* y y)) (* z z))
(= (gcd x y z) 1)))
(let ((result '()))
(for x in 1 .= n
(for y in (+ x 1) .= n
(for z in (+ y 1) .= n
(when (primitive-pythagorean-triple? x y z)
(set! result (cons (list x y z) result))))))
(sort result (lambda (x y) (< (third x) (third y))))))
(display (pythagorean-triples 37))
(newline)