Exercise 2.41

合計がsになる正の整数三つの組み合わせ(整数上限がn)という解釈でよろしいか。
unique-pairsを利用するならペアの後ろの数字未満の連番をくっつければいいきがする。あとは合計がSか判定。
まずはunique-triples。

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

と、uniue-pairsをまず実行し、そのそれぞれの末尾に付け足す方向で考えた。
これを実行するとこんなエラーが。

gosh>(unique-triples 5)
gosh> *** ERROR:peration + is not defined between -1 and (1)
Stack Trace:_______________________________________
  0  (enumerate-interval 1 (- (cdr i) 1))
        At line 138 of "(stdin)"
  1  (map proc seq)
        At line 53 of "(stdin)"

なんぞこれw
+なんて使ってないけど……とりあえずデバッグ
enumerate-intervalの辺りがおかしそうなのでテスト

(enumerate-interval 1 (- (cdr '(1 2)) 1))

と試すと同じエラー。さらに狭める。

(- (cdr '(1 2)) 1)

また同じ。と、流石にこの辺りでアホの俺でもきづくぜ。
-1と(2)では計算できないってことに!
だが単純に

(- 1 (2))

とすると

gosh> *** ERROR:nvalid application:2)

なんだよな。

(- 1 '(2))

だと

gosh> *** ERROR: operation + is not defined between -1 and (2)

ふむ。前者は2が関数だと思われてるんだろうか?
さらに実験。

(cdr '(1 2))
(2)
(car '(1 2))
1

carが1なのにcdrが(2)……。
(2)ってのは2とnil(じゃなかった空リスト)のリストだからか。
うーん。じゃあcdrをcadrにすればいいんじゃね?

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

(unique-triples 5)

gosh> ((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))

動いた!
スゲー
ていうか本当は上のは問題考えてるときは動かなくて途中でチートしたのであった。たぶん下が正解。

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

こっちは自分の考えの逆。つまり連番つくってその下にunique-pairsを入れる。
どう見てもこっちのがスマートです、本当に(ry
だがこの顛末をこうしてテキストにまとめてる間に自分アルゴリズムのほうでも解けたのでよかった
っていうか俺scheme素人すぎだろw
ちょっと仕様書読んでみるかー50ページぐらいらしいし。

追記:ってこのリストの要素がSと等しいかを調べる部分が抜けてたがこれはまあいいでしょ。