;; Pythagorean triples using combinations.

(use-modules (srfi srfi-1))

(define (combinations sequence k yield)
  (let loop ((rest sequence) (n k) (out '()))
    (if (zero? n)
        (yield (reverse out))
        (pair-for-each (lambda (p)
                         (loop (cdr p) (- n 1) (cons (car p) out)))
                       rest))))

(define (primitive-pythagorean-triple? x y z)
  (and (< x y z)
       (= (+ (* x x) (* y y)) (* z z))
       (= (gcd x y z) 1)))

(define (pythagorean-triples n)
  (let ((out '()))
    (combinations (iota n 1) 3
      (lambda (v)
        (apply (lambda (x y z)
                 (when (primitive-pythagorean-triple? x y z)
                       (set! out (cons v out))))
               v)))
    (sort out (lambda (x y) (< (third x) (third y))))))

(for-each (lambda (x) (format #t "~A~%" x)) (pythagorean-triples 53))