第12夜:ピタゴラスの宮殿

数の悪魔*1を題材にSchemeの勉強の最終回です。三角数の計算方法です。

よろしい、ドリス。じゃ、よく聞いて。前に座ってる1番目の生徒が、ええっと、アルバートだよね、そう、アルバートがパンを1個もらうことにする。つぎに2番目の生徒のベッティーナは、パンを2個もらうことにする。チャーリーは3個、ドリスは4個、という具合にして、38番目の生徒までいくことにしよう。じゃ、いいかな、計算して。こんなふうにして教室のみんなにパンを配るには、パンは何個いりますか - ボッケル先生

三角数の計算です。本の中ではn*(n+1)/2の式を変形させて、n/2*(n+1)で計算しています。

(define (show-triangler-number n)
	(define (answer n h)
		(format #f "~% ~D x ~D = ~D~%" h (+ n 1) (* h (+ n 1))))

	(define (number v) (format #f " ~3D" v))

	(define (dot-join proc l)
		(define (dot-iter l nl)
			(if (null? l)
				(string-join (reverse nl) "")
				(dot-iter (cdr l)
					(cons (apply proc (car l)) (cons " ..." nl)))))
		(dot-iter (cdr l) (cons (apply proc (car l)) '())))

	(define (dup-number n v)
		(do ((i n (- i 1))
			(l '() (cons (number v) l))) ((< i 1) (string-join l ""))))

	(define (format-number n v op)
		(define (format-number-iter n v l)
			(if (< n 1)
				(string-join (reverse l) "")
				(format-number-iter (- n 1) (op v 1) (cons (number v) l))))
		(format-number-iter n v '()))

	(define (some-numbers n h)
		(string-join (list
			(format-number h 1 +)
			(format-number h n -)
			(make-string (* 4 h) #\-)
			(dup-number h (+ n 1))
			(answer n h)
		) "\n"))

	(define (many-numbers n h)
		(string-join (list
			(dot-join format-number (list (list 3 1 +) (list 2 (- h 1) +)))
			(dot-join format-number (list (list 3 n -) (list 2 (+ h 2) -)))
			(make-string (* 4 6) #\-)
			(dot-join dup-number (list (list 3 (+ n 1)) (list 2 (+ n 1))))
			(answer n h)
		) "\n"))

	(if (odd? n)
		"Sorry, please even number."
		((if (< n 12) some-numbers many-numbers) n (/ n 2)))
)

(define (main args)
	(print (show-triangler-number 38))
0)

抽象化するスタイルが良く分からなくて、中途半端に抽象化しています。要修練です。結果はこちら。

   1   2   3 ...  18  19
  38  37  36 ...  21  20
------------------------
  39  39  39 ...  39  39

 19 x 39 = 741

本はこれで終わりです。ありがとうございました。

参考にさせていただきました:三角数 - Wikipedia

*1:Hans Magnus Enzensberger,1997,Der Zahlenteufel,エンツェンスベルガー 丘沢静也(訳),2000,数の悪魔,晶文社