SchemeとCommon Lispってどう違うんですか?

名前が違うよね。

  • いや、そういうことじゃなく…

一番違うのは名前空間だろうか。Common Lispは関数と変数で名前空間が違うから。あとは継続の有無か。

名前を保管している場所が異なるということ。Common Lispでは変数の名前は変数でまとめてあるし、関数の名前は関数でまとめて記憶している。君だってスズキという魚と鈴木という人とを同じ方法で記憶しているわけではないでしょう?頭の中でその2つは切り分けられているって感じない?

  • うううむ。じゃあSchemeでは変数と関数は同じ名前空間を使うんですか?

そうそう。だからSchemeではhogeという関数が定義されているときにhogeという変数を定義しようとすると関数の方は上書きされてしまう。一方でCommon Lispでは同じ名前の関数と変数が共存できる。関数hogeと変数hogeは同時に存在できるってこと。それは関数と変数の名前空間が別になっているからだね。非関数型の言語では関数と変数の名前空間は普通別々になっている。でもLispでは関数も一種のデータと見ているから、名前空間は別に一つでもいいんだ。関数がデータの一種なら、関数自体を関数の引数にとれるし、変数に関数を代入することも出来るし、逆に関数に他の値を代入することも出来る。

  • え、それじゃその関数使えなくなっちゃうじゃないですか。

それはその通りだけれど、関数を特別扱いしないでデータとして扱えるっていうことは、例えば配列に関数を格納していったりもできるということで、より柔軟な操作ができるようになる。オブジェクト指向の命令型言語なんかだと、関数とデータをまとめて格納するために特殊なデータ構造を持っているでしょう。クラス定義とかして。あれは関数をデータとして扱わずに、「特別なもの」としてしまったがために必要になったデータ構造なんじゃないのかと思うなあ。Lispなら関数とデータを構造体とかリストでまとめたっていいんですからね。

  • 関数もデータなんですよね?じゃあCommon Lispがデータと関数とで別の名前空間を使うのはおかしいじゃないですか。

まあそういう考え方もある。私も個人的にはScheme名前空間の扱いの方が自然に感じる。Common Lispではシンボルが指しているのが変数なのか関数なのか、そのままでは分からない。だから関数であることを示すために、特殊な記法を使わなければならなくなる。

(map + '(1 2 3) '(3 2 1))
> (4 4 4)

このように、Schemeでは関数を引数にとる関数には関数のシンボルを指定してやるだけでいいけど、Common Lispでは

(mapcar #'+ '(1 2 3) '(3 2 1))
> (4 4 4)

のように#'(シャープクォート)をつけて、+が関数であることを言わないといけない。さもなくば+という変数として扱われるというわけ。