#:g1: frontpage

 

setqの引数の謎

Posted 2016-07-29 13:03:45 GMT

SNSでsetqは一度に複数の変数を代入できて、引数が奇数個の場合はnilが返る、という説明を目にしました。
コードにすると、

(setq x 1 y)
→ nil

(list x y)(1 nil)

のような動作です。

Common Lispでは奇数個の引数の場合はエラーなので、もしやEmacs Lispのことかと思って確認してみましたが、どうもEmacs Lispではそのようです(最近のバージョンでは成立しない:詳細は後述)

この仕様はなかなか面白いので、Emacsを含む他のMACLISP系Lispではどうなっているのか確認してみました。

MACLISP

本家MACLISPです。

  • 0引数 → エラー
  • 1引数 → エラー

MACLISPで育ったrmsの設計したelispなので、実はMACLISPから引き継いだ仕様だろうと思っていましたが、意外にも0、1共にエラーとなりました。

(setq)

;((SETQ)) ODD NUMBER OF ARGS - SETQ ;BKPT WRNG-NO-ARGS (setq x)

;((SETQ X)) ODD NUMBER OF ARGS - SETQ (setq x 42) 42

Common Lisp

  • 0引数 → nil
  • 1引数 → エラー

です。

Franz Lisp

Franz Lispも、Common Lispと同じく

  • 0引数 → nil
  • 1引数 → エラー

でした。

-> (setq)
nil
-> (setq x)
Error: odd number of args to setq

Lisp Machine Lisp

CADR System 78.48では、

(setq)
NIL
(setq x)
NIL
x
NIL

のように、

  • 0引数 → nil
  • 1引数 → nil

となりました。
しかし、System 99では、

  • 0引数 → nil
  • 1引数 → エラー

のようです。ソースを確認してみましたが、古いバージョンでは、

(DEFUN SETQ (&QUOTE &REST SYMBOLS-AND-VALUES)
  (PROG (VAL)
   L    (COND ((NULL SYMBOLS-AND-VALUES) (RETURN VAL)))
        (SET (CAR SYMBOLS-AND-VALUES) (SETQ VAL (EVAL (CADR SYMBOLS-AND-VALUES))))
        (SETQ SYMBOLS-AND-VALUES (CDDR SYMBOLS-AND-VALUES))
        (GO L)))

のようになっています。
このコードを眺めた限りでは、値を省略した場合に値がnilとなるのは、『nilcadrnilだから』のようで、どうも偶々に見えます。
後にエラーにされるのでバグだったと言っても良いかなと思います。

Emacs Lisp

Emacs 25.0.50では、

  • 0引数 → nil
  • 1引数 → nil

Emacs 25.1.50では、

  • 0引数 → nil
  • 1引数 → エラー

となりました。

どうやら最近この動作は修正されてしまったようです。

ソースを確認してみると、値を省略した場合にnilとなるのは、Lisp Machine Lispと同じく、nilcadrnilだからのようで偶発的なもののようです。

Arc

この仕様で思い出したのがArcですが、Arcの場合は意図的な仕様です。

(set x)
→ t

x → t

しかし、setより良く使われる=は、setの上位互換の筈ですが、

  • 0引数 → nil
  • 1引数 → nil

となっています。
1引数の場合にtが代入されないのは何故かな思い追い掛けてみましたが、どうもマクロ展開時のパタンマッチで、偶々nilが入ってしまっているようにも思えます。
具体的なコードにすると、

((fn ((a b)) (list a b)) '(0))(0 nil)

的な動作の結果ですが、nilcadrnilの遠縁とも言えそうです。

まとめ

どうでも良いところを掘り下げてみましたが、最近elispの仕様が変更になったらしい、ということが判明したりで面白いなと思いました。

もしかすると、『可変長引数でかつ、ペアで処理しなくてはいけない場合に奇数個の場合の対処を忘れる』という典型的なバグ(もしくはミスフィーチャー)なのかもしれません。


HTML generated by 3bmd in LispWorks 7.0.0

実用Common LISP を読んだ

Posted 2016-07-25 15:37:50 GMT

実用Common LISPという本は実は2種類あるのですが、PAIPの翻訳ではなく、1987年に発行された 衣笠成一著の方です。

jitsuyo-cl

以前から一度読んでみたいなと思っていましたが、Amazonのマーケットプレイスで1500円位だったので購入してみました。

本の内容について

1987年という時代を反映してか、まず最初に人工知能について軽い解説があります。
後は、Common Lisp(1984)の標準関数についての解説が、機能ごとに章立てされ、そこそこ網羅的に記述されています。

解説は、どこかのマニュアルを書き写したようなものではなく、著者の言葉で解説されているという感じで、なかなか分かり易かったりもしますが、ちょっと間違った解説も散見され若干残念です。

例えば、stable-sortの解説等ですが、

;; stable-sortはコピーを作ってソーティングする.sortより安全性がある.

(stable-sort (copy-list '((1 2) (5 9) (3 2) (8 1)))
             #'>
             :key #'cadr)
==> ((5 9) (1 2) (3 2) (8 1)) 

となっていたりします。

コード例は、安定ソートを説明するためのものに見えるので、マニュアルを解釈する際の著者の勘違いでしょうか。

この本の面白いところ

非常にどうでも良い所ではありますが、個人的に興味を惹かれたのは、コードの出力例に利用されている処理系が、HPのCommon Lispである、HP Common Lispであることです。
HPのCommon Lispは、最初は、Portable Standard Lisp(PSL)をCommon Lispに仕立てた独自のものでしたが、後にLucid CLのOEM版処理系に置き換わります。

この本で利用されているのは、どうもPSLベースの処理系のようなので、この辺りがとてもレア。 とはいえ、それ以上のことは何もありません……。

まとめ

なかなか小気味良くまとまった本でしたが、こういうコンパクトな感じでANSI Common Lisp解説書があったら良いのになと思いました。

当然ではありますが、この本はCommon Lisp(1984)仕様の本ですし、2016年の今Common Lispの参考書として利用するような本ではありません。

とはいえCommon Lispマニアの方にも、それ程面白味もなさそうです。


HTML generated by 3bmd in LispWorks 7.0.0

Common Lispと猫

Posted 2016-07-03 14:01:43 GMT

ANSI Common Lispの規格書には猫が登場します。 登場する場所は、22.3.7.2 Tilde Left-Bracket: Conditional Expression

で、format指示子の~[の箇所です。

"~[Siamese~;Manx~;Persian~:;Alley~] Cat"

のようなコード例中に登場しますが、

(dotimes (i 5)
  (format T "~&i = ~D — ~[Siamese~;Manx~;Persian~:;Alley~] Cat~%" i i))
⊳ i = 0 — Siamese Cat
⊳ i = 1 — Manx Cat
⊳ i = 2 — Persian Cat
⊳ i = 3 — Alley Cat
⊳ i = 4 — Alley Cat
→ nil 

のような機能になります。

登場する猫の種類は、

  • シャム(サイアミーズ)
    siames
  • マンクス
    manx
  • ペルシャ(パージャン)
    persian
  • 野良
    alley

です。野良(雑種)も勘定して全4種。

この解説は、CLtL2でも見たことがあるなと思ってCLtL2を確認してみましたが、CLtL2にもそのままありました。

更に遡ってCLtL1を確認しましたが、CLtL1でもそのままでした。

もしやCLtL1では、Lispマシンのマニュアル(所謂Chinual)のformatの内容を再利用していたりしないかなと思いChinualを確認してみたところ、22.4.1 The Format Function(エラーで見れない)に記載がありました。

こちらは、

"~[Siamese ~;Manx ~;Persian ~;Tortoise-Shell~;Tiger ~;Yu-Shiang ~]kitty"

"~[Siamese ~;Manx ~;Persian ~;Tiger ~;Yu-Shiang ~:;Bad ~] kitty"

という風になっていて、シャム、マンクス、ペルシャは同じですが、

  • サビ(柄)子猫
    tortoise-shell
  • 虎(柄?)子猫
  • Yu-Shiangの子猫
  • 悪い子猫

が増えています。
Yu-ShiangはMITハッカー御用達の中華料理店だと思いますが、そこに猫でもいたのでしょうか。

Chinualに関しては、1979年あたりの第2版には既に登場しているようなので、formatがドキュメント化されたのと同時に登場したのかもしれません。

まとめ

特に意味もなくCommon Lisp(Lisp Machine Lisp)の仕様書に登場する猫を追い掛けてみました。
~[は猫を連想して暗記するのも良いかもしれません。

他に猫が登場する箇所があったら教えてください。


HTML generated by 3bmd in LispWorks 7.0.0

ANSI Common Lispの規格書(に近いもの)のPDFを入手する

Posted 2016-06-30 17:58:13 GMT

ANSI Common Lispの規格書を入手となれば当然ANSIが出しているので、ANSIから入手することになります。
現在PDFで$60のようなので約6,000円でしょうか。

しかし、このPDFは、紙媒体をスキャンした画像をPDFとしていて、検索もできないし電子媒体としては出来がひどいことで知られています。

さて、では、お馴染のLispWorksのHyperSpecや、FranzのFranz online ANS for Common Lispはどこから電子データを持ってきているのかというと、ANSIに持ち込む前のドラフトを元にしています。

HyperSpecの方はどの時点のものかは不明ですが、Franzの方は、dpANS2を元にしているという解説ページがあります。

このページにはdpANSが3つあると解説されていますが、この3つのdpANSは、CMUのAIリポジトリ等入手可能です。

今回は、このうちdpANS3RからPDFを作成してみます。

dpANS3RからPDFを作成する

用意するもの

  • dpans3のdviファイル
  • DVI→PDF変換ツール(dvipdf)
  • PDF結合ツール(pdftk)

まず、上記CMUのサイトからdpans3r.tgzとdpans3.tgzをダウンロードします。

$ wget http://www.cs.cmu.edu/afs/cs/Web/Groups/AI/lang/lisp/doc/standard/ansi/dpans/dpans3.tgz
$ wget http://www.cs.cmu.edu/afs/cs/Web/Groups/AI/lang/lisp/doc/standard/ansi/dpans/dpans3r.tgz

あとは展開して、DVIファイルをPDFに変換し、結合するだけです。

$ tar xvf dpans3.tgz
$ tar xvf dpans3r.tgz
$ mv dpANS3R/* dpANS3/
$ cd dpANS3
$ gunzip *.dvi.Z
$ for f in chap-*.dvi;do dvipdf $f;done
$ pdftk chap-0.pdf chap-1.pdf chap-2.pdf chap-3.pdf chap-4.pdf \
chap-5.pdf chap-6.pdf chap-7.pdf chap-8.pdf chap-9.pdf chap-10.pdf \
chap-11.pdf chap-12.pdf chap-13.pdf chap-14.pdf chap-15.pdf \
chap-16.pdf chap-17.pdf chap-18.pdf chap-19.pdf chap-20.pdf \
chap-21.pdf chap-22.pdf chap-23.pdf chap-24.pdf chap-25.pdf \
chap-26.pdf chap-a.pdf cat output dpANS3-15.17.pdf

以上の操作で、電子データとして中身の検索も可能な、dpANS3-15.17.pdfが生成されます。

なお、手元のANSI INCITS 226-1994(R2004)のPDFのページ数を確認すると表紙も含めて全体で1153ページですが、dpANS3では1360ページあります。
上述のCL Untold Storyによると、縦方向のスペースを調整した結果200ページも圧縮されたらしいです。

まとめ

ANSI規格の著作権は、ANSIが所有することになるようです。
規格をまとめたコミュニティ側としては、パブリックドメインにしたかったようですが、この辺りの経緯はCommon Lisp: The Untold Story - nhplace.comで語られています。

dpANSがリファレンスとして加工されて利用されるのにはこんな経緯がありますが、dpANSのTeXについては、Kent Pitman氏の見解によれば、派生、再配布、自由とのことです。


HTML generated by 3bmd in LispWorks 7.0.0

LispWorks IDE起動時のツールを指定する

Posted 2016-06-25 13:55:41 GMT

問題:

起動時のデフォルトだとGCモニターとリスナーが起動してくるがこれを変更したい

解決策:

lispworks-tools::*default-tools* で指定する

デフォルトだと、lispworks-tools::*default-tools*は、(lispworks-tools:lispworks-echo-podium lispworks-tools:listener)ですが、これを変更することで起動時のツールを変更できます。

設定は、~/.lispworks 等で可能です。

;;; ~/.lispworks
(setq lispworks-tools::*default-tools* '(lispworks-tools:editor))

仕組み

デフォルトのツールは、lispworks-tools:start-lispworksで起動しますが、起動時のツールは、:tools引数で指定することになっていて、初期値は、lispworks-tools::*default-tools* になっています。

lispworks-tools::*default-tools*の初期値は、(lispworks-tools:lispworks-echo-podium lispworks-tools:listener)です

所感

マニュアルに記載がないようですが、これは書いてて欲しい……。

  • env:start-environment
  • method-function env-internals:environment-start env::capi-environment

disassembleして眺めて、lispworks-tools:start-lispworksに辿り着き、lispworks-tools::*default-tools*変数を見付けました。


HTML generated by 3bmd in LispWorks 7.0.0

GNU Emacs の ledit-mode の謎

Posted 2016-06-22 15:15:10 GMT

EmacsにはLisp編集支援モードのledit-modeというものがかなり古くから標準で同梱されています。
しかし、このledit-modeですが実際に使っているという人や、利用方法の紹介などのブログ記事もこの十数年で見掛けたことは一度もありません。
ledit-modeのソースを眺めてみると分かりますが、現在では使い方も良く分からない代物となっています。

leditといえば、MACLISPをEmacsから利用する環境の名前でもあるのですが、ソース上のキーバインドから類推するに、どうもそれをGNU Emacs + Franz Lispで実現したもののように思えます。

以前、Franz LispをSIMH上のUltrix 4.0上で動かしてみたりしましたが、最近rshでのファイル転送も上手く行くようになったので、VAX Ultrix用にビルドされたEmacsとFranz Lispでこのledit-modeがどのように機能するのか試してみることにしました。

VAX UltrixのEmacsを用意する

世界にはVAX UltrixでGNU Emacs 21.4.1をビルドして配布している酔狂な方がいらっしゃるので、ありがたく使わせて頂きます。

/freeware以下に展開するのが前提のようなので、/freewareディレクトリを作成して展開します。

leditの設定

Emacs側だけでなく、Franz Lisp側でもledit.lleditcfns.o というファイルが必要になります。
(以前はGNU Emacsに添付されてきていたようですが、現在は添付されていないようです。)
leditcfns.cがあるディレクトリで、make leditcfnsすれば、leditcfns.oができますので任意のディレクトリに配置します。
Franz Lispの標準のライブラリのディレクトリは、/usr/lib/lispのようなので、下記では、ここに設置することにします。

次に、設置場所に応じてledit.lleditcfns.oの読み込み場所を書き換えます(標準のパスであればファイル名のみで良いようです)

(cfasl "leditcfns.o" '_switch_to_proc 'emacs)

後は

$ liszt ledit

で、ledit.oを生成することができるので、これをまたライブラリパスに置いておきます。

ledit の操作

MACLISPのleditと同じく、Emacsとlisp処理系を行ったり来たりするのにUNIXのジョブコントロールを利用するようです。
Emacsをサスペンドさせ、処理系を起動し、処理系をサスペンドし、Emacsを起動し……というのを交互に繰り返します。
Emacsからは、Franz Lispのインタプリタのlispと、コンパイラのlisztに移行することが可能です。

利用に際して、lisplistz、をバックグラウンドとして起動してemacsを起動します。

なお、Emacs側のコマンドは下記の通りです。

  • ledit-save-defun (c-m-d)
  • ledit-save-region (c-m-r)
  • ledit-go-to-lisp (c-x z)
  • ledit-go-to-liszt (c-m-c)

試しに下記のようなファイルの場合、

(load 'flavors)
(load 'describe)

(defflavor foo (x y z) () :initable-instance-variables :settable-instance-variables :gettable-instance-variables)

(setq foo (make-instance 'foo ':x 0 ':y 1 ':z 2))

(describe foo)

Emacsのバッファ上で、c-x h c-m-r c-x z すると、lisp に切り替わって、

%?lisp

[3]+ Stopped emacs bash$ %?lisp lisp ;Reading from LEDIT: [load /usr/lib/lisp/flavors.l] [fasl /usr/lib/lisp/vanilla.o] ; t ; foo ; fclosure[6] fclosure[6], an object of flavor foo, has instance variable values: x: 0 y: 1 z: 2

; fclosure[6] t ->

というような結果になります。
ここからemacsに復帰するには、c-eの後に改行を入力します。

まとめ

Emacsのledit-modeを実際にFranz Lispとの組み合わせで動かしてみました。
最新のEmacs 25でもledit-modeは(require 'ledit)で利用することが可能なようですが、

  • ターミナルで動かすことが前提
  • 最新のGNU EmacsとFranz Lispが同時に動く環境は存在しない
  • Franz Lisp側のコードが添付されてこない

等の理由で、実質機能しないライブラリとなっています。
削除してしまっても困る人はいないと思われますが、恐らくledit-modeが何物なのか不明なので削除して良いのかも判断できず、そのまま生き残っているのではないでしょうか。
一体いつまでGNU Emacsに添付され続けるのかこれからも見守り続けたいと思いますが、Franz Lispを最新の環境で動くようにすれば、このライブラリは生き返ることになりますし、Franz Lispを最新の環境でビルドできるようにする酔狂な人の登場も期待しています。


HTML generated by 3bmd in LispWorks 7.0.0

Common Lispのクラス構造のMembership Loopsの謎

Posted 2016-06-12 14:30:43 GMT

Common Lispのクラス構造では、

(type-of (find-class 'standard-object))
;=> standard-class 

(type-of (find-class 'standard-class))
;=> standard-class 

(subtypep 'standard-class 'standard-object)
;=> t 
;   t 

という風に循環を有する構造になっています。

しかし、この仕組みがどのような理由で採用されたのかについては、めぼしい資料もないようです。
Lisp仲間の小出さんとお話をすると、RDFでも同様の構造が現われているそうで、Common Lispがこの構造を採用した理由が知りたいものだ、という話に度々なっていました。

この循環をRDFでは、Membership Loopsと表現しているようなので、このエントリーでもMembership Loopsと呼ぶことにします。

小出さんはセマンティック・ウェブを専門とされていますが、このMembership Loopsについても以前お書きになっています。

Common-base vs. Mixin-base

以前、1988年辺りにまとめられていたCLOSの仕様のMOPの部分をTeX原稿からorgモードのファイルに変換して眺めたりしてみていましたが、

この資料を改めて眺めてみると、「Class Organization in the CLOS Kernel」の段で、


Class Organization in the CLOS Kernel

The earlier version of this section has been removed since it was too concerned with design rationale and not concerned enough with the user ramifications of the design decision.

This section should layout the class organization we decide on and then describe how it is supposed to be used. It will need to talk about the how users are expected to define subclasses of standard-class which specialize or override behavior.

For now, the class organization described below is the one (in PCL) where all the classes are subclasses of standard-class and standard-class is a subclass of object. Once we get that locked in, we will have to write this section.


とありました。
どうも以前のバージョンには詳しく書いてあったようですが、時期尚早ということで削除になったようです。
それならばということで、以前の版を探してみたところ、1987年の9月頃の版には詳しい記述がありました。

長いですが、そのまま引用すると、


Class Organization in the CLOS Kernel

The purpose of this section is to present the design rationale for why we defined standard-class as one class rather than as a subclass of the minimal class and some mixin classes for other features. The reason this belongs here is because you need to be able to understand the philosophy behind the design of the current class structure to understand how to program with it. In the following section, we present the standard classes defined in the CLOS kernel.

In the design of the lattice of these classes, there is a major design choice that deserves some discussion. The two choices that we want to contrast are the mixin-base versus common-base designs. (The style implemented in CLOS is the common-base design.) For this part of this discussion we will only talk about design of the standard metaclasses, and then extend it to the other metaobjects.

In the mixin-base design style, features of classes would be be partitioned among a number of different mixins, each of which supports a particular capability. Standard-class would then be a direct subclass of an appropriate set of these mixins, built-in-class would have another set of superclasses, etc. For example, there would be a class, called say primitive-class, that contained just those slots and methods that any object that could be a class must have. Other mixins, including something like obsoletable-metaclass, instance-slot-metaclass, class-slot-metaclass, (or should it be slotted-class) initarg-metaclass would also be direct superclasses of standard-class. These would each bring in to standard-class a few slots and behaviors that were appropriate to that type of class. Other metaclasses, such as built-in-class and structure-class would have the appropriate subset of these and other mixins.

In the common-base design style, the class standard-class is the root of the metaclass lattice, and all other metaclasses are subclasses of this class. In this design, all the features in standard-classes are implemented directly for standard-class. For subclasses of standard-class like built-in-class, features that are not allowed must be “turned off” by specializing the appropriate generic function.

It would be nice to have a picture here. We just put defclass forms for now because drawing pictures is so hard.

Common base:

(defclass standard-class ()
    (..))
(defclass built-in-class (standard-class)
    (..))
(defclass structure-class (standard-class)
    (..))
(defclass forward-referenced-class (standard-class)
    (..))
(defclass funcallable-standard-class (standard-class)
    (..))

Mixin base:

(defclass primitive-class ()
    (..))
(defclass nameable-class (primitive-class)
    (..))
(defclass built-in-class (nameable-class)
    (..))
(defclass structure-class (slotted-class nameable-class)
    (..))
(defclass slotted-class (primitive-class)
    (..))
(defclass standard-class (obsoletable-class slotted-class)
    (..))
(defclass funcallable-standard-class (standard-class)
    (..))

Arguments for mixin-base style:

By dividing the functionality of standard-class into many mixins, one can potentially define mixins that capture behavior associated with a form of type abstraction. This might allow easier understanding of the capabilities of any class that includes a subset of these type mixins, since the behaviors of each mixin should be independent and additive. Use of these “type” mixins to add behavior to a class implies that there is no need to turn off unwanted behavior, since all behaviors are invoked through specific generic functions. Unwanted behaviors would have no applicable method for classes that did not include such a mixin. Test for the availability of a particular behavior can be done using typep, since behaviors are intimately tied to classes.

Arguments for common-base style:

All the classes in CLOS are implemented as instances of standard-class. By including in one class all the behavior useful for standard-class, one gets a minimal self supporting kernel. This is minimal in several senses. First, the bootstrap implementation of classes need only have the single class standard-class that is its own class. Secondly, once one has understood the features of standard-class one has a complete view of the underlying implementation. Finally, this requires fewer classes in the kernel.

Using the common-base style, one does not have to make and defend decisions about the division of behaviors among mixins. For example, should there be one mixin or two that implement the notions of class and instance slots. Should there be a separate mixin for the standard initialization mechanism. Should there be a separate mixin that support default-initforms. Having the mixins is fine if you have cut the world exactly right for the variation of class behavior one wants. However, if not, then one has the same type of problem with overriding unwanted behavior with multiple mixins.

The test for availability of a particular behavior can be done by defining a generic-function that acts as a predicate, making the default method return NIL, and defining a method for any class that supports the behavior subclasses which “turn off” that behavior must redefine this method. Although this requires some extra mechanism, it allows independent implementation of a behavior in two different classes without insisting that to support the same behavior one needs to share a common superclass.

Another reason why we want to encourage users to make their classes subclasses of either standard-class or structure-class is that we don't specify a portable mechanism for extending the type system. In other words, the user must use the mechanism provided by standard-class or structure class for determining the class of objects. Finally, there is an argument that the current Common Lisp type system is not partitioned into mixins that support common behavior (e.g. where is ceiling for float and rational). Hence trying to use this style in the rest of CLOS wouldn't make the system be uniform in any way.

For us the balance of these arguments weighed in favor of the common-base style. Thus for each of the classes in the kernel below, there is a standard-x class at the top of the lattice that captures the common behavior. For unwanted behaviors, there are methods on generic-functions that signal an appropriate error. For example, for built-in-class, an error is signalled if the user tries to update the class an provides slots for the class. In the description of the generic function in the kernel, each method that has an error case is indicated.


という風に、common-baseとmixin-baseが検討されていたようです。
それで紆余曲折があってcommon-baseが採用されたと思われますが、ここから決定までの経緯はあいかわらず不明です。

この時期のCLのオブジェクト指向システムのメーリングリストの議論も眺めてみると、何点か該当するものがあります。

ざっと眺めたところでは、mixin-baseの方が筋は良いだろうとされているようですが、

  • 上手く機能やプロトコルをmixinとして分割できるとは限らない。
  • 既に参照実装であるPCL(Portable CommonLoops)では、common-baseでやってきて、それなりの知見もある

等々の理由で、その後mixin-baseが推されることもなく、そのままcommon-baseの流れになっていったようにも見えます。
正しい方法が分からないので実装が選択できるようにすべき、という話もあったようですが、その後特に誰かが行動を起こしているような所もなく、何よりmixin-baseが実装され検証される、ということもなかったようです。

しかし、現状の構成では、standard-classに一本化されている訳でもなく、built-in-class や、 structure-class 等も存在するので、明示的なmixin元は存在しないものの、standard-class とは違う属性をmixinしている何かとも解釈できなくもなさそうです。

まとめ

どうやらCommon LispのMembership Loopsについては、RDFのように理論的裏打ちがあった上での構成ではなく、機能の分割も検討してみたけど、丸ごとで提供する今の構成に落ち着いてしまった結果に見え、クラスや集合論的見地からの構成ではなさそうに見えました。

ちなみに、Common Lisp Object System Specificationの3章は完成することはなかったのですが、今回saildartのTeX原稿をPDFにしてみたら、それらしき体裁のものができたので興味のある方は見てみて下さい。

また、この件について何か詳細をご存知の方は是非とも教えて頂けると嬉しいです。


HTML generated by 3bmd in LispWorks 7.0.0

Common Lisp Recipes を読んだ

Posted 2016-05-26 16:22:50 GMT

前にこのブログでも、

''755ページもあり、まだ自分は7章までしか読んでいないですが、Common Lispを日常的に書く人には必携の書という感じです。
全部読んだら感想でも書いてみようかなと思っています。''

などと書いていましたが、Common Lisp Recipes — A Problem-Solution Approach(以下CLR)を半年掛けてやっと読み終えました。
当初は、一日75ページのペースで読み進めていたので1月中に読了かと思っていましたが、何ヶ月か放置してしまっていました。
しかし、引っ越しをして通勤時間が激増したのでKoboに入れて通勤時間中に読むようにしたところ約2週間で読了となりました。

この本の対象読者について

この本の前書きにも書いてありますが、基本的な所は、Practical Common Lisp(実践Common Lisp)を参照することとして、その次のステップに当たる実践的なレシピ集という位置付けになっています。 マクロ等の解説も、On LispやLet Over Lambdaがあるので、そちらに任せているということで棲み分けがされているようです。

CLRは、On LispやLet Over Lambdaのように、なんだか良く分からないが凄そう、というような所は全くなく外連味もないので、ガチでCommon Lispを書いてないとあまり嬉しくない内容なのが特徴でしょうか。
しかし、ガチで書いている人には必読の内容で、実に細かく実践的に解説されているので、実践Common Lispを読了した位の人であれば、通読すればCommon Lispの書法が1ランクアップするに違いないと思います。
また、ある程度他の言語を齧ってからCommon Lispに入門する人が多いと思いますが、他の言語の経験から類推していても分からないような部分についての解説が大盛りです。Common Lispらしい方法と用意された道具を知るにもとても良い本だと思います。

また、Stack Overflowで質問されそうな基礎的な大体載っているので頭に入れておくと学習時間の節約にもなりそうです。

いまどきのライブラリの解説が少ないという指摘もあるようですが、Common Lispに備わっている機能をかなり詳しく解説していて、個人的にはCommon Lisp固有の機能を徹底的に解説しているこのような本のほうが貴重だと思いました。

CLRがCommon Lispの基本機能の解説を押えてくれた、とも考えられるので、今後さらに応用寄りの解説書が出版されることを期待したいところです。

そういば、MOP周りはこの本ではあまり解説されていませんので、その辺りも今後の方々に期待したいところです。

一応Common Lispのエキスパートも想定読者層ではないようですが、この本で取り上げられている事項すべてに通暁している人というのは多くはなさそうです。

印象に残ったところ

まず、シンボルの解説から始めているのが渋いです。
また、配列、ストリーム、コンディション周り解説はなるほどなと思うことが多かったです。

気になるところ

全編サンプルコードの書法では、関数をfunction(#')ではなく、quote(')で記述していますが、これがちょっと個人的には残念です。
また、functionを100%排除しているわけでもなく、ちょっと不思議でもあります。
書籍としての見栄えを優先したのか個人の趣味なのか。
quoteにしてしまうと、情報量が落ちるのであまり良いスタイルとも思えないですし、古えの1970年代Lispっぽいです。

例えば、 (map 'list 'list '(a b c))

と書くと型としての'listと関数としての'listが並ぶので気持ち悪かったり(この書籍でもmapの関数では、#'が使われていたりします)

まとめ

Common Lispをガチで書く人で、より知識を深めたい人は、買って損はないです。
Apressでは電子書籍はセールで価格が40%offになったりすることがままあるようなので、それを狙って購入してみるのも良いかもしれません。


HTML generated by 3bmd in LispWorks 7.0.0

Chez Scheme がオープンソース化されたので試してみる

Posted 2016-05-05 14:59:16 GMT

先日の4/26日の話になりますが、商用Scheme処理系の雄であるChez SchemeがApache License, Version 2.0で公開されました。

結構反響は大きいようですが、早速ダウンロードして試してみます。

$ git clone https://github.com/cisco/ChezScheme.git
$ cd ChezScheme/
$ ./configure --threads --64

今回試すホストはLinuxですが、何も指定しないとシングルスレッド版になるようです。
上記では、マルチスレッド版になるように指定しています。これでビルドすると、ta6le版がビルドされます。

また、

$ make test

でビルドのチェックも可能です。
しかし、トレースの出力結果もテストするのは初めてみたような…。
なお、make checkには結構時間がかかります(多分1時間以上)
ta6le/mats/summaryに結果が出力されます。

インストールは、

$ sudo make install

のようになります。 Chezの処理系であるscheme、お馴染のPetite Chezのpetite、それとスクリプト実行用なのか、scheme-script等々がインストールされます。

起動してみる

$ scheme

で起動します。

$ scheme
Chez Scheme Version 9.4
Copyright 1984-2016 Cisco Systems, Inc.

>

なにはともあれfibを定義してみましょう

(define (fib n)
  (if (< n 2)
      n
      (+ (fib (- n 1))
         (fib (- n 2)))))

(time (fib 40)) ;>> (time (fib 40)) ;>> no collections ;>> 0.958591374s elapsed cpu time ;>> 0.958607953s elapsed real time ;>> 0 bytes allocated ;=> 102334155

さすがネイティブコンパイラだけあって速いですね。
LispWorks(ネイティブコンパイラ)位の速度が出てます。

他に何か試してみようと物色していましたが、 @nfunatoさんにChezでも採用されているNanopass Compilerの動画を教えてもらったので、これを眺めつつ、この動画で紹介されている scheme-to-c を試してみます。

Clojure Conj 2013: Andy Keep - Writing a Nanopass Compiler

scheme-to-c は nanopass-framework に依存していますが、下記の版の nanopass-framework-scheme でないと上手く動かないようです。

それぞれgit cloneすればOKです。

使用方法はREADMEに書いてありますが、下記ではコマンドラインからのオプションの指定ではなく、処理系内からライブラリのディレクトリの指定と読み込みを実行しています。

(cd ".../scheme-to-c")

(library-directories (cons '(".../nanopass-framework-scheme" . ".../nanopass-framework-scheme") '(("." . "."))))

(import (c))

またまたfibを実行

(time
 (my-tiny-compile
  '(letrec ((fib (lambda (n)
                   (if (< n 2)
                       n
                       (+ (fib (- n 1))
                          (fib (- n 2)))))))
     (fib 40))))
(time (my-tiny-compile (quote (...))))
    no collections
    0.003715930s elapsed cpu time
    1.254270947s elapsed real time
    155104 bytes allocated
102334155

scheme-to-cはCに変換して実行し、結果をChezに戻してくるというものですが、コンパイルの速度も実行結果も速いですね!

(trace-passes #t)

を実行することでトレースも可能で、ナノパスコンパイルの細かいパスの具合や、変換されたCのコードなども眺めることが可能です。

まとめ

速さを求めるならRacket、Larceny、Chickenあたりかと思っていましたが、Chezはさすがネイティブという速度です。
これだけ速いと比べてみたくなりますが、Chezが公開されたこのタイミングでベンチを取って公開する人も現われました。

まだ一覧としては未完成のようですが、これまでの所でもやはりChezは高速なようです。


HTML generated by 3bmd in LispWorks 7.0.0

Common Lispの機能大盛りでズンドコキヨシ

Posted 2016-03-21 17:12:12 GMT

Common Lispの機能大盛りでズンドコキヨシを書いてみました。
大分無理矢理です。

(eval-when (:compile-toplevel :load-toplevel :execute)
  #+cmucl   (import 'pcl:funcallable-standard-class)
  #+sbcl (import 'sb-mop:funcallable-standard-class)
  #+allegro (import 'mop:funcallable-standard-class)
  )

;;; utilities (defun lsh&inc (n delta bytespec) (ldb bytespec (+ (ash n 1) delta)))

(define-modify-macro lsh&incf (delta bytespec) lsh&inc)

;;; (defconstant kiyoshi-state #b11110 "ズン = 1, ドコ = 0 ズンズン ズンズン ドコ = 11 11 0")

(define-condition kiyoshi () ())

(defclass zundoko-function (standard-generic-function) ((state :initform 0)) (:metaclass funcallable-standard-class))

(defgeneric zundoko (zd) (:method ((zd (eql 0))) (write-line "ドコ")) (:method ((zd (eql 1))) (write-line "ズン")) (:generic-function-class zundoko-function))

(defmethod update-zundoko-function-state ((zd integer) (gf (eql #'zundoko))) (lsh&incf (slot-value gf 'state) zd (load-time-value (byte (integer-length kiyoshi-state) 0))))

(defmethod reset-zundoko-function-state ((gf (eql #'zundoko))) (setf (slot-value gf 'state) 0))

(defmethod zundoko :after (zd) (when (= kiyoshi-state (update-zundoko-function-state zd #'zundoko)) (write-line "キ・ヨ・シ!") (reset-zundoko-function-state #'zundoko) (signal 'kiyoshi)))

(handler-case (loop (zundoko (random 2))) (kiyoshi ())) ;>> ドコ ;>> ズン ;>> ドコ ;>> ズン ;>> ズン ;>> ドコ ;>> ズン ;>> ズン ;>> ズン ;>> ドコ ;>> ズン ;>> ズン ;>> ズン ;>> ズン ;>> ドコ ;>> キ・ヨ・シ! ;>> ;=> nil #-allegro (quit) #+allegro (exit)


HTML generated by 3bmd in LispWorks 7.0.0

Older entries (2005 remaining)