Schemeの“ポインタ”のようなもの、或いは『Scheme入門』をGaucheで読む（1.5）

set-car!/set-cdr! で思ったように行かなかったので色々試行錯誤した結果、分かったことを記しておきます。

環境はEmacsでGauche。

```scm
(set-car! '(2 2 3) 1)
```

で

```scm
(1 2 3)
```

と評価されるだろうな、と思っていたら

gosh> #\<undef\>

となって、どうすればいいんだろ？　と試行錯誤したところ

```scm
(define x '(2 2 3))
```

とリストを定義してからから

```scm
(set-car! x 1)
```

とするとやはり
gosh> #\<undef\>
と評価されますが、x自体を評価しますと

```scm
(1 2 3)
```

と評価されます。
これはおそらく、set-car!/set-cdr! が単にリストの 先頭/その残り を入れ替えるのではなく、（この場合）**xの指すコンスセルの car/cdr 部へ代入** なのだろうと思われます。
こんな感じなんじゃないでしょうか？

![リスト.jpg](https://qiita-image-store.s3.amazonaws.com/0/113031/9de95127-5920-449b-c32e-e87cc33b1c7c.jpeg)

この、「xの**指す**コンスセルの car/cdr 部へ代入」てさー……

**所謂、ポインタだよね。**C言語でいうところの。
……うん、知ってた。ポインタの無いプログラム言語なんて無いって、知ってた。

ともかく、Schemeにおける set-car!/set-cdr! がポインタ（矢印）なのだろうと言うことがよく分かる例に、queue を挙げます。参考例は
[「Scheme 入門10. 代入」](http://www.shido.info/lisp/scheme_asg.html)
の
4.1. 待ち行列 (Queue) の実装
より。

ところでこのページののっけから「代入（むやみに）使うべからず」のように注意されてますし、最後にも「関数型で代入はあんまし使わない」というようなことが書かれてますよね。
さらに上述した例、


```scm
(define x '(2 2 3))

(set-car! x 1)
```

のような用法に至っては「プログラミングGauche」（Kahuaプロジェクト (著), 川合 史朗 (監修, 監修)　2008年　オライリージャパン）P121のコラムで
「本当はやってはいけない」
とまで書かれてます。
いやはや、関数型におけるset!一族のこの嫌われようと言ったら。一体何やらかしたんだ、set!一族。関数型言語業界のお偉いさんの娘にでも手を出したのか。

そんなset!系ですが、取り敢えず教科書に載ってる以上使ってみないわけにもいかず、使う以上、使い方も知らないわけにいかんのです。きっと若気の至りだったんです、許してあげてください、関数型言語業界のお偉いさん。

さて「4.1. 待ち行列 (Queue) の実装」のうち、make-queue と enqueue! だけGaucheでやってみました。コードは紹介した
[「Scheme 入門10. 代入」](http://www.shido.info/lisp/scheme_asg.html)
で見るなりコピペするなりしてください。

それでは括弧打ち開始。

```scm
(define q (make-queue))
```
で　q というqueueを作ります。この時点で q を評価すると

gosh> (())

となります。今の q はこんな感じですな。
![queue1.jpg](https://qiita-image-store.s3.amazonaws.com/0/113031/dcf32822-cc43-4c9e-ae75-c479f3b49502.jpeg)

それから

```scm
(enqueue! q 'a)
(enqueue! q 'b)
(enqueue! q 'c)
```
とやっていきますと**評価するつど**
gosh> (a)
gosh> (a b)
gosh> (a b c)
と評価されます。
ところが**q 自体を評価しますと**
gosh> ((a b . #0=(c)) . #0#)

……何だこの謎のリストは。

うーん、と悩みに悩み（本当はそこまで悩まず）ググったところ、いらっしゃるものですね、同じような箇所で嵌った方が。はい、[こちら](http://okwave.jp/qa/q5409829.html)です。公式（？（と言うか作者の川合史朗氏のサイト））への[リンク](http://practical-scheme.net/wiliki/wiliki.cgi?Gauche%3A%E5%BE%AA%E7%92%B0%E3%83%AA%E3%82%B9%E3%83%88%E3%81%AE%E8%AA%AD%E3%81%BF%E6%9B%B8%E3%81%8D)
も貼ってあります。ありがたや。
\#0=(c)
は、(c)に #0 というラベルをつけて、同じオブジェクトを #0# で表しているようです。つまり
((a b . #0=(c)) . #0#)
は
((a b . (c)) . (c))
つまり
((a b c) c)
で、 enqueue!関数 の最後で queue を car しているので ((a b c) c) の car である(a b c)が返されるんですな。
試しに

```scm
(enqueue! q 'a)
```
の時点で q を評価すると
gosh> (#0=(a) . #0#)
と返ってきます。つまり
((a) . (a)) すなわち ((a) a) です。この状態をコンスセルで表すと
![queue2.jpg](https://qiita-image-store.s3.amazonaws.com/0/113031/b4e14ad9-1bfa-8c05-daa8-886799b92c99.jpeg)
このように、**同一の** (a) が q の car部 cdr部にポイントされていて、それらが**それぞれの** (a) では**無い**ことを示すために
gosh> (#0=(a) . #0#)
と記されるようです。
その後順次

```scm
(enqueue! q 'b)
(enqueue! q 'c)
```
とやっていくと
![queue3.jpg](https://qiita-image-store.s3.amazonaws.com/0/113031/400a3392-ff0a-c0e4-f876-730ce5110675.jpeg)
そーれから♪
![queue4.jpg](https://qiita-image-store.s3.amazonaws.com/0/113031/993ff575-f3e8-74db-0d7d-95788301f1b9.jpeg)

と、 q の cdr部をポイントするコンスセルが次々と最後のコンスセル（この場合は (a) から (b) 、(b) から (c) ）に変わっていき、そしてそれらのコンスセルは q のcar部にポインタされた最初のコンスセル（この場合は (a) ）から次々につなげられて（ポインタされて）いくので、q をcar すると (a b c) が返ってくるわけですね……うーん、よくもまあ、こんなアクロバティックなコード、というか技法を思いつくものだなぁ。

なので q 自体を評価すると car部に  (a b c) が、 cdr部に (c) がポイントされていて、そしてこの (c) はcar部の   (a b c) の最後のコンスセルである (c) と同一であることを示すため、単に
((a b c) c)　｛もしくは((a b . (c)) . (c))｝
ではなく
((a b . #0=(c)) . #0#)
と記されるようです。（ちょっとこんがらがってきた）

では湯浅太一著『Sheme入門』(岩波書店　1991年）の96ページ、巡回リストをやってみましょう。

```scm
(define x '(eat rice))

(set-cdr! x x)
```
さて x を評価しますと……

gosh> #0=(eat . #0#)

と返ってきました。これはコンスセル x の cdr部にコンスセル x 自体が入っている、ということですね。リストにすると

(eat . (eat . (eat . (eat . ……（事象の地平の彼方で） (eat . (eat))))……（事象の地平の彼方で）))

で、結果
(eat eat eat eat eat eat  ……（事象の地平の彼方で） eat)
となります。
同書には「こういうことが起こるから強制終了の仕方を調べてやるように」ということが書かれていますので私は
「Gauche暴走開始！　Emacsごと強制終了させます！　カウントよろしく！」
「３！　２！　１！」
「Emacs可動停止！　Gaucheも活動を止めました！」
とやる気まんまんだったので、ちょっと残念でした。