(関数)と(関数 nil)の違い

(関数)と(関数 nil)との違いなんて、考えられることなんてこれしかないわけで、まあ確かめてみれば実に明らか。
まずはリストかどうか確認です。

> (listp '(func))
t
> (listp '(func ()))
t

はい、これくらいは通過しますよね。そりゃあね。
で、本命のcdrチェック!

> (cdr '(func))
nil
> (cdr '(func ()))
(nil)

そうだよねぇ、そうなるよねぇ。*1
というわけで、(x)と(x nil)とはコンスセルとしても異なるものであることが確認されました。


これで解決ならよかったのですが、(x)と(x nil)との違いがどうして存在するのかを考えて見ると、それほど自明じゃないんですよね。nilはアトムでありリストでもあるので、nilと(nil)との区別を付けようと思ったらアトムnilとリストnilとが異ならなきゃ無理じゃないか、と思ってしまったのです。
しかし、なんとかその辺を解決する妥協点の結論を考えたので、ちょっとメモっておきます。
まず、(x)とは(x . nil)のことで、(x nil)と同一とは言えないということから始めましょう。試すまでもなくわかることですが、(x . y)のcdr部はyで(x y)のcdr部は(y)ですから、先ほど試したふたつのリストもこのような構造をしていると考えるのが自然でしょう。
では(x . y)と(x y)とはどう違っているのでしょうか。そう、(x . y)ではyは(x . y)のコンスセルのcdr部にそのまま乗っています。それに対し(x y)ではyは(y . nil)という新しいコンスセル上にあり、(x y)のcdr部からそのセルへリンクがいっているわけです。
ここまで来ればわかるでしょうが、(x nil)というのはcar部から新しいコンスセル(nil)へのリンクが伸びているのです。その新しいコンスセルはnilではない実体なわけですね。それに対し(x . nil)というのはそのcar部がnilそのもの(へのリンク)。
そう考えれば、nilが神のようなものだと考えてもなんとか説明が付くかなーと思います。発想が若干C言語的かもしれない。

*1:ブルーハワイ味