73 lines
2.3 KiB
Racket
73 lines
2.3 KiB
Racket
#lang sicp
|
|
|
|
(#%require "ambeval.rkt")
|
|
|
|
(define (require p)
|
|
(if (not p) (amb)))
|
|
|
|
(define (an-element-of items)
|
|
(require (not (null? items)))
|
|
(amb (car items) (an-element-of (cdr items))))
|
|
|
|
(define (an-integer-starting-from n)
|
|
(amb n (an-integer-starting-from (+ n 1))))
|
|
|
|
(define (a-pythagorean-triple-between low high)
|
|
(let ((i (an-integer-between low high)))
|
|
(let ((j (an-integer-between i high)))
|
|
(let ((k (an-integer-between j high)))
|
|
(require (= (+ (* i i) (* j j)) (* k k)))
|
|
(list i j k)))))
|
|
|
|
;; Exercise 4.35
|
|
(define (an-integer-between low high)
|
|
(require (<= low high))
|
|
(amb low (an-integer-between (+ low 1) high)))
|
|
|
|
;; Exercise 4.36
|
|
|
|
;; To generate all pythagorean triples, it is not sufficient to
|
|
;; replace an-integer-between with an-integer-starting-from because
|
|
;; this would attempt to search through all k, then all j and then all
|
|
;; i. As such, we'd never get to the second value of j or i.
|
|
;; Instead, we need to visit the values of i, j and k diagonally to
|
|
;; ensure that they are visited in order.
|
|
|
|
(define (a-pythagorean-triple)
|
|
(let ((t (a-triple-with-sum-from 3)))
|
|
(let ((i (car t))
|
|
(j (car (cdr t)))
|
|
(k (car (cdr (cdr t)))))
|
|
(require (= (+ (* i i) (* j j))
|
|
(* k k)))
|
|
(list i j k))))
|
|
|
|
(define (a-triple-with-sum-between low high)
|
|
(let ((i (an-integer-between 1 high)))
|
|
(let ((j (an-integer-between i (max 1 (- high i)))))
|
|
(let ((k (an-integer-between j (max 1 (- high j i)))))
|
|
(let ((sum (+ i j k)))
|
|
(require (>= sum low))
|
|
(require (< sum high))
|
|
(list i j k))))))
|
|
|
|
(define (a-triple-with-sum-from n)
|
|
(amb (a-triple-with-sum-between n (+ n 1))
|
|
(a-triple-with-sum-from (+ n 1))))
|
|
|
|
;; Exercise 4.37
|
|
|
|
;; Alternative version from the book. I think this will be more
|
|
;; efficient because it only has to explore the values of k that are
|
|
;; sums of the squares of i and j, rather than all integers from j up
|
|
;; to high.
|
|
(define (a-pythagorean-triple-between* low high)
|
|
(let ((i (an-integer-between low high))
|
|
(hsq (* high high)))
|
|
(let ((j (an-integer-between i high)))
|
|
(let ((ksq (+ (* i i) (* j j))))
|
|
(require (>= hsq ksq))
|
|
(let ((k (sqrt ksq)))
|
|
(require (integer? k))
|
|
(list i j k))))))
|