「Scheme入門」（湯浅太一 著：岩波書店 1991年）をGaucheで読む（2.5）、或いは震える顔文字生成関数作成


今回はGaucheとTUTSchemeの違いで引っ掛かったというわけでは無いのですが、「Scheme入門」を（Gaucheで）読んでいて疑問に思ったこととその解決を記しておきます。

６章関数の演習問題、[6.3.2]です。「任意の個数のリストを引数にして、それらを一つのリストにするmy-append関数を作る」ですね。（解答はP148）

```scm

(define (my-append . x)
  (letrec [[append2
	    (lambda (x y)
	      (if (null? x)
		  y
		  (cons (car x) (append2 (cdr x) y))
	      )
	    )
	  ]]
    (if (null? x)
	'()
	(append2 (car x) (apply my-append (cdr x)))
    )
  )
)

```

（注：括弧及びインデントは**私が**読みにくいので**私が**変えて書いてあります）
局所関数ではちょっと分かりにくいので、補助関数を別に作って書き直します。traceして結果が分かりやすいからね！……誰だ？　今、「これだからにわかLisperはさぁ」と言った奴は。

```scm

(define (append2 x y)
  (if (null? x)
	  y
	  (cons (car x) (append2 (cdr x) y))
  )
)


(define (my-append . x)
  (if (null? x)
      '()
      (append2 (car x) (apply my-append (cdr x)))
  )
)

```

両方とも再帰を使ってますが、違いがあります。後者は apply を使っています。
で、考えました。
「cdr してくんだからどの道最終的に () [nil] になるんじゃね？　apply、要らなくね？」
ね、バカでしょ？　さらにバカにも程がある、apply を省いて実行してみました。

```scm

（注：やらないほうがいいですよ）

(define (my-append . x)
  (if (null? x)
      '()
      (append2 (car x) (my-append (cdr x)))
  )
)

```

おや？　何の反応も無いぞ？　何も評価結果が表示されない。何でだ……おい、マウスカーソルがカクカクするぞ。
システムモニターを見るとCPUがテンパってました。
「Gauche、暴走を始めました！」
「Emacsごと強制停止しろ」（cv:立木文彦）
「カウントお願いします！」
「３！、２！、１！」
「Emacs強制停止！　Gauche、活動を停止しました！」

……何でだよ？　分からん。分からないあまりTwitterで「解せぬ」とぶちぶち愚痴っていますと、[@anohana](http://twitter.com/anohana) さんが教えてくれました。
子曰く、apply無しに於いてmy-appendへは引数が必ず一つ渡され、(null? x)成立すること能わず、と。

あー、はー、ははぁー。な〜るほ……ど？　ん？……んん？　いや、再帰でcdrしてcdrし尽すんだから最終的にはmy-appendに渡る引数は絶対 '() になるんじゃないのか、な？　な？
そんなこんなで「Scheme入門」を読み返したり禁断（併読ができない性格だから）の「プログラミングGauche」をひもといたりと丸二日ほど考えまくって、ようやく「あ。my-appendの引数は、(my-append . x)と残余パラメータ（「プログラミングGaucheでは「可変長引数」）の形で定義されているから、例えば '(a) を渡すと ((a)) として渡されるわけか。ははーん、は、はぁ〜ん」と、気付きましたと、さ。

つまり
1.(my-deppend '(a) )
とリストを渡すと、
2.(~~apply~~ my-append (cdr x))
では
3.(~~apply~~ my-append (cdr ((a)) )
となり
4.(my-append () )
になるわけですが、 my-append の引数は**リスト化される（括弧にくるまれる）**ので、またもや
5.(~~apply~~ my-append (cdr x))
は
6.(~~apply~~ my-append (cdr (()) )
となり cdr しても cdr しても括弧がついて[(())になって]返ってくるという無限ループに陥るわけですな。
はい、そこで **apply** です。引数をリストで渡すと**括弧を剥がして**関数に渡してくれるapplyです。なので
(define (my-appned . x)
　　　...)
と定義して
(my-deppend '(a) )
とリストを残余パラメータ（可変長引数）として渡し、((a)) とリスト化されても
(apply my-append (cdr ((a)) )
ならばそれ即ち
(apply my-append () )
となり、そこでようやく
(if (null? x)
　...)
に引っ掛かって終了してくれるのですね。
###結！論☆###
残余パラメータ（可変長引数）と apply はセットにして覚えといた方がいいみたいです。


これで納得して先に進んでおけば（そしてユーロ'16がなければ）今頃読み終えられていただろうに、「引数が残余パラメータの関数は、呼び出される都度、その引数がリスト化される」を使って遊んでみようと思ったばかりに姉さん、俺、どつぼにハマりました。
「この括弧を操れるなら……顔文字を作られる関数が出きるんじゃね？」
作りたかった関数は
(f x y)
とすると、「x が y 個の括弧に包まれる」関数です。
まず書いてみたのはこんな。

```scm

(define (my-listx x) 
  (do
      ((n 0 (+ n 1)))
      ((= n x))
    ((lambda x x) 1)))

```

予想では x 回数、１がリスト化（括弧に包まれ）て
(my-listx 3)
とすると
(((1)))
となる予定、でした。ヘイ！ C+x C+e！

```

gosh> #t
```

いや……いやいやいや！　真偽を判定して欲しいわけじゃないから！
仕様が無いのでまずは list 関数と同じ関数を作りますか。

```scm

(define (my-list . x) x)

```

然る後に

```scm

(define (my-listx x)
  (do ((n 0 (+ n 1)))
      ((= n x)
    (my-list 2))))

(my-listx 5)

```

予想では(((((2))))) となるんじゃないかな？
さてC+x C+e！

```

gosh> #t
```
……だからぁ！真偽判定して欲しいわけじゃないってば！
ようし、じゃあGaucheにある~~関数~~ 構文、while使っちゃうぞ。

```scm

(define (my-listx x)
  (let ((n 0))
    (while (< n x)
	   (my-list 1)
	   (set! n (+ n 1)))))


(my-listx 4)

gosh> #t

```

```scm
(define (my-listx x y)
  (let ((n 0))
    (while (< n y)
	   (list x)
	   (set! n (+ n 1)))))


(my-listx 3 4)

gosh> #t

```

オーケー、オーケー。代入使ってやんよ。この際 set! 使ってやるわ。

```scm

(define (my-listx y . x)
  (do ((n 0 (+ n 1)))
      ((= y n) z)
    (set! z (my-listx y))))


(my-listx 2 3)

```

これで (((2))) となるんじゃ……**暴☆走しました☆**

```scm
(define (my-listx . x)
  (if (null? x)
      ()
      (my-listx x)))

(my-listx 3)
（これも暴走します）
```

すんませんでした。取り敢えずあまり考えもせず適当に思いついたコードを評価させてすんませんでした。すんませんでしたから暴走するのは勘弁してください。
その後も

```scm
(define (my-listx . x)
  (do ((n 0 (+ n 1)))
      ((= n 10)
       (my-listx x))))

(my-listx 3)
（暴走します）
```
やら

```scm
(define (my-listx . x)
  (do ((n 0 (+ n 1)))
      ((= n 10))
    (my-listx x)))

(my-listx 3)
（これも暴走するよー）

```

と暴走コードを書いてはEmacsごと強制停止させるを繰り返し、おとなしく 補助関数を使ってみましたよ。

```scm
(define (my-listx x y)
  (do
      ((n 0 (+ n 1)))
      ((= n y) x)
    (set! x (my-list x))))


(my-listx 2 4)

gosh> ((((2))))
```
こーゆー結果が欲しいの！

補助関数を局所関数にして一つのリストにしてみましょ。

```scm

(define (my-listx x y)
  (let [[my-list
	    (lambda z z)]]
    (do
	((n 0 (+ n 1)))
	((= n y) x)
      (set! x (my-list x)))))

(my-listx 1 5)

gosh> (((((1)))))
```

だがしかし、元々は残余パラメータ（可変長引数）が、リスト化されるのを利用したかったわけで。
こういうのはどうだろ？

```scm

(define (my-listx y . x)
  (do
      ((n 0 (+ n 1)))
      ((= n y) x)
    (set! x (my-listx x))))

(my-listx 2 1)

```

```
gosh> *** ERROR: real number required: (1)
Stack Trace:
_______________________________________
  0  (my-listx x)
        At line 43 of "(stdin)"

```

じゃあこういうのは？

```scm

(define (my-listx y . x)
  (do ((n 0 (+ n 1)))
      ((= y n) z)
    (set! z (my-listx x))))

(my-listx 3 'a)
```

```

gosh> *** ERROR: real number required: (a)
Stack Trace:
_______________________________________
  0  (my-listx x)
        At line 142 of "(stdin)"

```

エラーコードたちが何をrequireしているのかが分からんのだが。
その後も幾度も

```
gosh> *** ERROR: real number required
```
と怒られるも何故怒られているのか、そもそも怒っているのか分からないダメ出しをくらいつつ、もういい！　俺、do ループじゃなくて再帰使うよ！　暴走するなら暴走しろよ！　してみろよぉ！　と逆ギレして書いてみたのが

```scm

(define (my-listx x . y)
  (if (zero? x)
      y
      (my-listx (- x 1) y)
  )
)


(my-listx 3 'a)

gosh> ((((a)))) 

```

……あ、上手く行ってら。

最後に y が評価されるから x+1 個の括弧が付くけど
・残余パラメータを使い、
・その関数自体を繰り返し（再帰し）て
・set!（代入）を使わず
括弧の数を制御できるリスト作成関数が作成できました。

ようし、これを顔文字にしちゃうぞ。

```scm

(define (gakuburu x . y)
  (if (zero? x)
      y
      (gakuburu (- x 1) y)
  )
)


(gakuburu 5 '；ﾟДﾟ)

gosh> ((((((；ﾟДﾟ))))))
```

あっはっは！　めっちゃ震えとる！　西野カナばりに震えとる！
どうせなら「ｶﾞｸﾌﾞﾙ」と震えさせたいなあ、と思い

```scm

(define (gakuburu x . y)
  (if (zero? x)
      (begin
	(display "ｶﾞｸ")
	y
	(display "ﾌﾞﾙ")
      (gakuburu (- x 1) y)
      )
   )
)

```

としてみましたが

```
(gakuburu 3  '；ﾟДﾟ)

gosh> #<undef>
```

んー。まあ入出力はまだ先（11章）だからしょうがないか。だいたい私、まだ begin の使い方がまだよく分からないんですよね。

ということで今回はここまで。

参考：twitter.com/anohana/status/737065758052601857

###追記###

@tk_riple さんのコメントを読み、「ほほう、(flush) は良く分からんから取り敢えず else 句に (newline) 入れてみるか」と思ったところ致命的な勘違いをしていたことに気付きましたよ。
……else句が無い。
これじゃそもそも再帰関数になってないじゃないですか。なので書き直し。

```scm

(define (gakuburu x . y)
  (if (zero? x)
      (begin
	(display "ｶﾞｸ")
	(display y)
	(display "ﾌﾞﾙ")
      )
      (gakuburu (- x 1) y)
   )
)
```

これで

```scm

(gakuburu 2 '；ﾟДﾟ)

gosh> ｶﾞｸ(((；ﾟДﾟ)))ﾌﾞﾙ#<undef>
```

と表示されるようになりました。最後の
\#\<undef\>
は依然、謎のままだであるが……それは後に語られる物語であろう。