計算機プログラムの構造と解釈 第二版 P72 問題2.41

このときの俺、実行結果にコメントを書くのが流行っていたようだ。

#!/usr/local/bin/gosh
;; -*- coding: utf-8 -*-

(use ggc.debug.trace)
(use math.mt-random)

(define nil '())


(define (accumulate op initial sequence)
  (if (null? sequence)
    initial
    (op (car sequence)
        (accumulate op initial (cdr sequence)))))


(define (flatmap proc seq)
  (accumulate append nil (map proc seq)))


(define (enumerate-interval low high)
  (if (> low high)
    nil 
    (cons low (enumerate-interval (+ low 1) high))))


(define (filter predicate sequence)
  (cond ((null? sequence) nil)
        ((predicate (car sequence))
         (cons (car sequence)
               (filter predicate (cdr sequence))))
        (else (filter predicate (cdr sequence)))))


(define (unique-pairs n)
  (flatmap
    (lambda (i) 
      (map (lambda (j) (list i j))
           (enumerate-interval 1 (- i 1))))
    (enumerate-interval 1 n)))


(define (unique-list3 n)
  (flatmap
    (lambda (i)
      (map (lambda (j) (cons i j))
           (unique-pairs (- i 1))))
    (enumerate-interval 1 n)))


(define (summation sequence)
  (if (null? sequence)
    0
    (+ (car sequence)
       (summation (cdr sequence)))))


(define (sum-check n s)
  (filter (lambda (x) (= (summation x) s))
          (unique-list3 n)))


;; main
(define (main args)

  (display "まず、ユニークな3つの数のリストをつくる。")(newline)
  (display "ここまで勉強してきているとわかるが、")(newline)
  (display "前項までのユニークな組み合わせに、後の項を再帰的に付け足せばいい")(newline)
  (display (unique-list3 5))
  (newline)
  (newline)


  (display "後はリストを足し算するものを作っておけば、割と簡単")(newline)
  (display "(sum-check 5 8): ")
  (display (sum-check 5 8))
  (newline)

  0)


実行

まず、ユニークな3つの数のリストをつくる。
ここまで勉強してきているとわかるが、
前項までのユニークな組み合わせに、後の項を再帰的に付け足せばいい
((3 2 1) (4 2 1) (4 3 1) (4 3 2) (5 2 1) (5 3 1) (5 3 2) (5 4 1) (5 4 2) (5 4 3))

後はリストを足し算するものを作っておけば、割と簡単
(sum-check 5 8): ((4 3 1) (5 2 1))

なるほど。