Archive for 8月, 2011

リリカルLisp ver1.5

火曜日, 8月 23rd, 2011

リリカルLisp ver1.5を公開しました。
約半年ぶりの更新です。

今回の変更点は、エラーのチェックです。
今までのバージョンでは、実引数が仮引数より多かろうが、少なかろうが、
未束縛の変数を使おうが、シンボルの足し算を行おうが、
どんな無茶をしても、(大抵の場合、意味のない)値が返ってきました。
それが、今回の変更で「エラーです」と通知する機能が付きました。

> x
エラー:top-levelにおいて、xは未束縛です
> (cons 1)
エラー:consに与える引数が少なすぎます
> (+ 'a 'b)
エラー:+において、aは数ではありません
> (let 3 4)
エラー:letの使い方が間違っています

大体こんな感じです。
日本語を選ぶのに苦労しました。

プログラミング言語の学習(した気分になる)ソフトなのだから、
このような機能は付いていて当たり前だとは思うのですが、
最初のバージョンでは時間の関係から付けることができませんでした。
そして、その後は、
「今更、そんなものつけてもなー」
という思いからずっと放置されてきました。

今になってエラーのチェックを付けた理由は、
次のようなメールがきたからです。

I can’t get past lesson 2. When I type
(define x 4)
the result is x
Then, when I type
(* (x+3) 4)
the result is -2358896
I thought it should be 28

なんというか、ごめんなさい。
もう放置しても誰も困らないだろうと思っていたけど、
そんなことはなかったみたいです。

余談ですが、
リリカルLispのソースをgithubで公開してからちょうど1年が過ぎました。
誰も触ってくれないだろうなと思っていたけど、
ほんとに誰も触ってくれませんでした。
ショックですっ ><

compileとcompile-fileの生成するコードは異なることがある

金曜日, 8月 19th, 2011

compileは対象の関数のみを見て最適化を行うのに対して、
compile-fileはファイル内すべての関数/変数を見て最適化を行えるので、
両者の結果が異なるのは、当たり前といえば当たり前です。
しかし、ファイルに単一の関数しかなくても、
compileとcompile-fileの生成するコードが異なることがあります。

(defun f ()
  (eq '(a b c) '(a b c)))

SBCLやAllegro CLにおいて、
関数compileでコンパイルした場合、(f)の値はNILとなりました。
しかし、関数compile-fileでこの関数をコンパイルすると、(f)の値はTとなりました。
#残念なことに、CLISP、Clozure CLではどちらの場合もNILとなりました。

さて、compile-fileした場合Tになる理由は前回のエントリを読んでください。
#前回の実験ではACLではcoalesceは行われませんでしたが、
#今回の実験ではcoalesceが行われているようです。
#恐らく、関数単位でcoalesceを行なっているのではないかと思います。

compileした場合にNILになる理由は、すばりcoalesceが行われていないからです。
では、何故coalesceが行われないかというと理由は簡単。
仕様でそう決まっているからです。

Literal objects appearing in code processed by the compile function are neither copied nor coalesced. The code resulting from the execution of compile references objects that are eql to the corresponding objects in the source code.

理由は分かるんですが、ややこしい話です。

コンパイルしたらあなたと合体した

月曜日, 8月 15th, 2011

Common Lispでは、
よく似てるけどeqlではない2つのリテラルを含むソースをコンパイルしたら、
コンパイル後には2つのリテラルがeqlになることがあるそうです。
そのことを「2つのリテラルはコンパイラによって合体された」と言うとか何とか。

ちゃんとした定義はこちら
(“similar”は「似ている」ではなく厳密な定義が与えられています)

coalesce v.t. (literal objects that are similar) to consolidate the identity of those objects, such that they become the same object. See Section 3.2.1 (Compiler Terminology).

The term coalesce is defined as follows. Suppose A and B are two literal constants in the source code, and that A’ and B’ are the corresponding objects in the compiled code. If A’ and B’ are eql but A and B are not eql, then it is said that A and B have been coalesced by the compiler.

ということで実際に試してみました。
使用したのはSBCL 1.0.50です。

(defvar a '(a b c))
(defvar b '(a b c))

こちらのソースコードをloadして (eql a b) を試したところ、NILになりました。
しかし、compile-fileしたものをloadすると、 (eql a b) の値はTになりました。
まさに2つのリテラルが合体したという感じです。

ちなみに、CLISP、Clozure CL、Allegro CLではcompile-fileしてもNILのままでした。
smilarなリテラルがたくさん出てくるようなソースコードでは、
リテラルを合体した方が、コンパイル後のバイナリファイルのサイズや、
ロードした際のヒープの使用量を節約できそうですが、
コピペを繰り返したソースでもない限り、効果は薄いような気がします。
誰かcoalesceの効果の程を測った人とかいないんでしょうかね。