数え上げたものを整形するナニ

accumulate とか filter とかも込みな手続きのセットが以下です。

(define (getChangePattern n)
  (accumulate cons
	      '()
	      (filter (lambda (x) (= (apply + x) n))
		      (enum-candidate n
				      (make-list n candidate-list)))))

(define (accumulate op init seq)
  (if (null? seq)
      init
      (op (car seq)
	  (accumulate op init (cdr seq)))))

(define (filter pred seq)
  (cond ((null? seq) '())
	((pred (car seq))
	 (cons (car seq)
	       (filter pred (cdr seq))))
	(else
	 (filter pred (cdr seq)))))

(define candidate-list '(50 25 10 5 1))

(define (make-list n l)
  (cond ((null? l) '())
	((>= n (car l)) l)
	(else
	 (make-list n (cdr l)))))

(define (enum-candidate n candidate)
  (define (ec-inner rslt lst candidate)
    (if (null? candidate)
	rslt
	(let ((test (append lst (list (car candidate)))))
	  (cond ((>= n (apply + test))
		 (let ((tmp (ec-inner (append rslt (list test))
				      test
				      (make-list (let last-i ((lst test))
						   (if (null? (cdr lst))
						       (car lst)
						       (last-i (cdr lst))))
						 candidate-list))))
		   (if (null? (cdr candidate))
		       tmp
		       (ec-inner tmp lst (cdr candidate)))))
		(else
		 (ec-inner rslt lst (cdr candidate)))))))
  (ec-inner '() '() candidate))

今回 UT 作らなかったのが敗因なんだろうな。作れたら作って追記してみます。

追記

UT 書いた。以下。

(use gauche.test)

(add-load-path ".")
(load "change")

(test-start "change")
(test-section "enum-candidate")
(test* "(enum-candidate 1 '(1))"
       '((1))
       (enum-candidate 1 '(1)))

(test* "(enum-candidate 2 '(1))"
       '((1) (1 1))
       (enum-candidate 2 '(1)))

(test* "(enum-candidate 3 '(1))"
       '((1) (1 1) (1 1 1))
       (enum-candidate 3 '(1)))

(test* "(enum-candidate 4 '(1))"
       '((1) (1 1) (1 1 1) (1 1 1 1))
       (enum-candidate 4 '(1)))

(test* "(enum-candidate 5 '(5 1))"
       '((5) (1) (1 1) (1 1 1) (1 1 1 1) (1 1 1 1 1))
       (enum-candidate 5 '(5 1)))

(test* "(enum-candidate 6 '(5 1))"
       '((5) (5 1) 
	 (1) (1 1) (1 1 1) (1 1 1 1) (1 1 1 1 1) (1 1 1 1 1 1))
       (enum-candidate 6 '(5 1)))

(test* "(enum-candidate 10 '(10 5 1))"
       '((10)
	 (5) (5 5) (5 1) (5 1 1) (5 1 1 1) (5 1 1 1 1) (5 1 1 1 1 1)
	 (1) (1 1) (1 1 1) (1 1 1 1) (1 1 1 1 1) 
	 (1 1 1 1 1 1) (1 1 1 1 1 1 1) (1 1 1 1 1 1 1 1)
	 (1 1 1 1 1 1 1 1 1) (1 1 1 1 1 1 1 1 1 1))
       (enum-candidate 10 '(10 5 1)))

(test* "(enum-candidate 15 '(10 5 1))"
       '((10) (10 5)
	 (10 1) (10 1 1) (10 1 1 1) (10 1 1 1 1) (10 1 1 1 1 1)
	 (5) (5 5) (5 5 5)
	 (5 5 1) (5 5 1 1) (5 5 1 1 1) (5 5 1 1 1 1) (5 5 1 1 1 1 1)
	 (5 1) (5 1 1) (5 1 1 1) (5 1 1 1 1) (5 1 1 1 1 1)
	 (5 1 1 1 1 1 1) (5 1 1 1 1 1 1 1) (5 1 1 1 1 1 1 1 1)
	 (5 1 1 1 1 1 1 1 1 1)
	 (5 1 1 1 1 1 1 1 1 1 1)
	 (1) (1 1) (1 1 1) (1 1 1 1) (1 1 1 1 1) 
	 (1 1 1 1 1 1) (1 1 1 1 1 1 1) (1 1 1 1 1 1 1 1)
	 (1 1 1 1 1 1 1 1 1) (1 1 1 1 1 1 1 1 1 1)
	 (1 1 1 1 1 1 1 1 1 1 1) (1 1 1 1 1 1 1 1 1 1 1 1)
	 (1 1 1 1 1 1 1 1 1 1 1 1 1) (1 1 1 1 1 1 1 1 1 1 1 1 1 1)
	 (1 1 1 1 1 1 1 1 1 1 1 1 1 1 1))
       (enum-candidate 15 '(10 5 1)))

(test* "(enum-candidate 16 '(10 5 1))"
       '((10) (10 5) (10 5 1)
	 (10 1) (10 1 1) (10 1 1 1) (10 1 1 1 1) (10 1 1 1 1 1)
	 (10 1 1 1 1 1 1)
	 (5) (5 5) (5 5 5) (5 5 5 1)
	 (5 5 1) (5 5 1 1) (5 5 1 1 1) (5 5 1 1 1 1) (5 5 1 1 1 1 1)
	 (5 5 1 1 1 1 1 1)
	 (5 1) (5 1 1) (5 1 1 1) (5 1 1 1 1) (5 1 1 1 1 1)
	 (5 1 1 1 1 1 1) (5 1 1 1 1 1 1 1) (5 1 1 1 1 1 1 1 1)
	 (5 1 1 1 1 1 1 1 1 1)
	 (5 1 1 1 1 1 1 1 1 1 1)
	 (5 1 1 1 1 1 1 1 1 1 1 1)
	 (1) (1 1) (1 1 1) (1 1 1 1) (1 1 1 1 1) 
	 (1 1 1 1 1 1) (1 1 1 1 1 1 1) (1 1 1 1 1 1 1 1)
	 (1 1 1 1 1 1 1 1 1) (1 1 1 1 1 1 1 1 1 1)
	 (1 1 1 1 1 1 1 1 1 1 1) (1 1 1 1 1 1 1 1 1 1 1 1)
	 (1 1 1 1 1 1 1 1 1 1 1 1 1) (1 1 1 1 1 1 1 1 1 1 1 1 1 1)
	 (1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
	 (1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1))
       (enum-candidate 16 '(10 5 1)))

(test* "(enum-candidate 25 '(25 10 5 1))"
       '((25)
	 (10) (10 10) (10 10 5)
	 (10 10 1) (10 10 1 1) (10 10 1 1 1) (10 10 1 1 1 1)
	 (10 10 1 1 1 1 1)
	 (10 5) (10 5 5) (10 5 5 5)
	 (10 5 5 1) (10 5 5 1 1) (10 5 5 1 1 1)
	 (10 5 5 1 1 1 1) (10 5 5 1 1 1 1 1)
	 (10 5 1) (10 5 1 1) (10 5 1 1 1) (10 5 1 1 1 1)
	 (10 5 1 1 1 1 1) (10 5 1 1 1 1 1 1) (10 5 1 1 1 1 1 1 1)
	 (10 5 1 1 1 1 1 1 1 1) (10 5 1 1 1 1 1 1 1 1 1)
	 (10 5 1 1 1 1 1 1 1 1 1 1)
	 (10 1) (10 1 1) (10 1 1 1) (10 1 1 1 1) (10 1 1 1 1 1)
	 (10 1 1 1 1 1 1) (10 1 1 1 1 1 1 1) (10 1 1 1 1 1 1 1 1)
	 (10 1 1 1 1 1 1 1 1 1) 
	 (10 1 1 1 1 1 1 1 1 1 1)
	 (10 1 1 1 1 1 1 1 1 1 1 1) 
	 (10 1 1 1 1 1 1 1 1 1 1 1 1)
	 (10 1 1 1 1 1 1 1 1 1 1 1 1 1)
	 (10 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
	 (10 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
	 (5) (5 5) (5 5 5) (5 5 5 5) (5 5 5 5 5)
	 (5 5 5 5 1) (5 5 5 5 1 1) (5 5 5 5 1 1 1)
	 (5 5 5 5 1 1 1 1) (5 5 5 5 1 1 1 1 1)
	 (5 5 5 1) (5 5 5 1 1) (5 5 5 1 1 1) (5 5 5 1 1 1 1)
	 (5 5 5 1 1 1 1 1)
	 (5 5 5 1 1 1 1 1 1)
	 (5 5 5 1 1 1 1 1 1 1)
	 (5 5 5 1 1 1 1 1 1 1 1)
	 (5 5 5 1 1 1 1 1 1 1 1 1)
	 (5 5 5 1 1 1 1 1 1 1 1 1 1)
	 (5 5 1) (5 5 1 1) (5 5 1 1 1) (5 5 1 1 1 1) (5 5 1 1 1 1 1)
	 (5 5 1 1 1 1 1 1)
	 (5 5 1 1 1 1 1 1 1)
	 (5 5 1 1 1 1 1 1 1 1)
	 (5 5 1 1 1 1 1 1 1 1 1)
	 (5 5 1 1 1 1 1 1 1 1 1 1)
	 (5 5 1 1 1 1 1 1 1 1 1 1 1)
	 (5 5 1 1 1 1 1 1 1 1 1 1 1 1)
	 (5 5 1 1 1 1 1 1 1 1 1 1 1 1 1)
	 (5 5 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
	 (5 5 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
	 (5 1) (5 1 1) (5 1 1 1) (5 1 1 1 1) (5 1 1 1 1 1)
	 (5 1 1 1 1 1 1) (5 1 1 1 1 1 1 1) (5 1 1 1 1 1 1 1 1)
	 (5 1 1 1 1 1 1 1 1 1)
	 (5 1 1 1 1 1 1 1 1 1 1)
	 (5 1 1 1 1 1 1 1 1 1 1 1)
	 (5 1 1 1 1 1 1 1 1 1 1 1 1)
	 (5 1 1 1 1 1 1 1 1 1 1 1 1 1)
	 (5 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
	 (5 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
	 (5 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
	 (5 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
	 (5 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
	 (5 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
	 (5 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
	 (1) (1 1) (1 1 1) (1 1 1 1) (1 1 1 1 1) 
	 (1 1 1 1 1 1) (1 1 1 1 1 1 1) (1 1 1 1 1 1 1 1)
	 (1 1 1 1 1 1 1 1 1) (1 1 1 1 1 1 1 1 1 1)
	 (1 1 1 1 1 1 1 1 1 1 1) (1 1 1 1 1 1 1 1 1 1 1 1)
	 (1 1 1 1 1 1 1 1 1 1 1 1 1) (1 1 1 1 1 1 1 1 1 1 1 1 1 1)
	 (1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
	 (1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
	 (1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
	 (1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
	 (1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
	 (1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
	 (1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
	 (1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
	 (1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
	 (1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
	 (1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
	 )
       (enum-candidate 25 '(25 10 5 1)))

(test-section "getChangePattern")
(test* "(getChangePattern 1)"
       '((1))
       (getChangePattern 1))

(test* "(getChangePattern 2)"
       '((1 1))
       (getChangePattern 2))

(test* "(getChangePattern 3)"
       '((1 1 1))
       (getChangePattern 3))

(test* "(getChangePattern 4)"
       '((1 1 1 1))
       (getChangePattern 4))

(test* "(getChangePattern 5)"
       '((5) (1 1 1 1 1))
       (getChangePattern 5))

(test* "(getChangePattern 6)"
       '((5 1) (1 1 1 1 1 1))
       (getChangePattern 6))

(test* "(getChangePattern 10)"
       '((10) (5 5) (5 1 1 1 1 1) (1 1 1 1 1 1 1 1 1 1))
       (getChangePattern 10))

(test* "(getChangePattern 15)"
       '((10 5) 
	 (10 1 1 1 1 1)
	 (5 5 5)
	 (5 5 1 1 1 1 1)
	 (5 1 1 1 1 1 1 1 1 1 1) 
	 (1 1 1 1 1 1 1 1 1 1 1 1 1 1 1))
       (getChangePattern 15))

(test* "(getChangePattern 25)"
       '((25)
	 (10 10 5)
	 (10 10 1 1 1 1 1)
	 (10 5 5 5)
	 (10 5 5 1 1 1 1 1)
	 (10 5 1 1 1 1 1 1 1 1 1 1)
	 (10 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
	 (5 5 5 5 5)
	 (5 5 5 5 1 1 1 1 1)
	 (5 5 5 1 1 1 1 1 1 1 1 1 1)
	 (5 5 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
	 (5 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1) 
	 (1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1))
       (getChangePattern 25))

(test-end)

結構ツラかったです。特に enum 方面。