I've taken some time to work through the generation of "prime pairs" from SICP Section 2.2.3 - Sequences as Conventional Interfaces, for example:
(1 3)
No, since sum = 4(1 4)
Yes, since sum = 5 (prime)
Here is what I have from scratch, which works:
#lang sicp
; RANGE helper function
(define (range a b) ; a to b
(if (> a b) nil
(cons a (range (+ 1 a) b))
))
; FILTER helper function
(define (filter func sequence)
(cond ((null? sequence) nil)
((func (car sequence)) (cons (car sequence) (filter func (cdr sequence))))
(else (filter func (cdr sequence)))))
; PRIME helper function
(define (prime? n)
(cond ((or (= n 1) (= n 2)) #t)
((=(modulo n 2) 0) #f)
(else ; see if no modulos=0 under length of sqrt(N)
(= 0
(length (filter (lambda (i) (eq? i #t))
(map (lambda (d) (= (modulo n d) 0)) (range 3 (sqrt n)))))))))
; MAP helper
(define (flatmap func seq)
(if (null? seq) nil (append (func (car seq)) (flatmap func (cdr seq)))))
And the actual function:
; generate pair of two numbers with 1 <= i < j <= N
(define (get-pairs n)
(flatmap (lambda (i)
(map (lambda (j)
(list i j))
(range 1 (- i 1))))
(range 1 n)))
(define (get-prime-pairs n)
(filter (lambda (p) (prime? (apply + p)))
(get-pairs n)))
(get-prime-pairs 4)
; ((2 1) (3 2) (4 1) (4 3))
Pretty neat. Now I'm trying to write the same function that instead of just doing pairs, will do a tuple of size
. Here is what I have so far for this:
(define (get-n-tuples size n)
(define (get-n-tuples-internal i args)
(cond ((= i size) (map (lambda (i) (cons i args)) (range 1 n)))
(else
(flatmap (lambda (k)
(get-n-tuples-internal (+ i 1) (cons k args)))
(range 1 n)))))
(get-n-tuples-internal 1 '()))
(define (get-prime-seqs size num)
(filter (lambda (p) (prime? (apply + p)))
(get-n-tuples size num)))
(get-prime-seqs 4 4)
; ...
; (3 2 4 4)
; (2 3 4 4)
; (1 4 4 4))
One thing which I've found difficult though is to remove duplicate within the function itself by doing something like (range i (- (min args) 1))
. So instead I've just used the same (range 1 n)
for all of the loops.
How would I properly convert this so that it emulates the initial function, so that each successive number in the list must be smaller, i.e., if there are three numbers in the sequence then 1 <= num1 < num2 < num3 <= N
, and a valid pair would be (4 2 1)
but not (1 2 4)
or (5 1 1)
?