#:g1: frontpage

 

「Clojureシンタックスハイライター 開発から考える これからのLispに必要なもの」の感想

Posted 2015-07-29 12:18:03 GMT

Lisp Meetup #30でathosさんの発表「Clojureシンタックスハイライター 開発から考える これからのLispに必要なもの」を面白くUstreamで観ました。

現場での盛り上がりが自分的には斜め上な方向に盛り上がっていた気がするので、自分も何か書いてみたいと思った次第です。
まあ、slideshareのコメントでもよいのですが。

全体的なところ

前提として、CASE: Computer-Aided Software Engineering等のツールは静的に適用するもの、というのがあったような気がしました。
確かにリーダーマクロや、マクロを多用されると処理系外部のツールが静的にチェックするのは大変です。

ただ、Lispの開発環境の歴史的にこの類のCASEツールが無かったのかというと、そういうことはなく、1980年代はSmalltalkと並んでトップを走っていたわけです。
但し、最近の傾向と違うのは、静的な外部ツールとの連携という方式ではなく、LispもSmalltalkも環境(世界)を内包しているので、CASEツールも内包されている所だと思います。

スライドにあるような、再実装するハメになるツールの例に挙がっているものも

  • IDE・エディタ
  • コードフォーマッタ
  • コーディングチェッカー
  • カバレッジ・ツール
  • メトリクス計測ツール

ほぼ全部、Lisp/Smalltalkには、1980年代には処理系(世界)に内包されていた感じです。
内包されているという性質上、個別に再実装されることもなく、APIも提供されていたりします。

そういう意味では、「プログラマと処理系だけがコードを読む牧歌的な時代」は1980年代にはLisp/Smalltalk界では終了し、新しいステップに進んでいたとは思います。

処理系が世界そのものであるか、処理系は世界の一部であるか

上に述べたように、Lisp、Smalltalkは、一ツールというよりは、世界/環境である訳です。
世界/環境というのはどの辺りまでの範囲かというと、大体OSと同じ範囲ですが、これには色々な流派がありました。
といっても、言語の処理系がOSにまで拡張したのは、Lisp/Smalltalk位かなと思います。

しかしもちろん、これらの方式は現在主流ではありません。
このままだと長々と書いてしまい終らなくなりそうなのですが、何が言いたいのかといえば、世界を提供するLisp/Smalltalkには、Lisp/Smalltalkなりのやり方がある(あった)のではないか、ということです。

まとめ

昔からあったんだ、といっても現行貧弱だったりする傾向はあるわけで、目を覚ませという話ではあると思いますが、知らなければ、Lispはずっと立ち後れている、という結論にもなってしまうので一応知ってて欲しいなと思った訳です。

まあ、現状が変わる訳ではないのですが。

これからのことを考えるとなれば、静的言語で発展した静的なツール/検査手法を動的言語でどう上手く利用するか、かなと思います。
両者の特性と歴史を知る必要があるのではないでしょうか。


HTML generated by 3bmd in LispWorks 7.0.0

Lispとエディタ (7)

Posted 2015-07-27 15:05:05 GMT

 今回は、2000年代のLispとエディタについて書いてみようと思います。といっても、トピックはほぼ無い感じなのですが、RedditでドイツのJoswigさんより色々と有益な情報を頂いたので、それを紹介しつつ終わりにしたいと思います。

WindowsプラットフォームでのIDEのエディタ

 2000年にもなると大分Windowsが世の中を席巻していましたが、LispベンダーのFranzとHarlequinもWindows版にはIDE付きのものを用意します。
HarlequinのLispWorksは元々あったIDEをWindows対応にし、Franzの方は、ExperTelligence社のProcyon CLという処理系を買収し、そのGUI環境を既存の環境と組み合わせたとのことです。
Procyon CLの紹介を眺めると、GUIのツールキットにCommon Graphicsとあり、現在のAllegro CLもCommon Graphicsなので、この辺りを吸収したのかなあと想像しています。

また、時代がちょっと戻りますが、DOSからWindowsに掛けてGoldhill社が出していた開発環境のGolden Common Lispは最高という話です。
確かに色々充実しているっぽいですが、一度触って確かめてみたい所です。

Goldhill社のLispといえば、Bit 1986年9月号には、「サンマルコLISP探検隊」という記事があるのですが、この中で、DOS版のGCLispの紹介があります。
サンマルコLISP探検隊というのは、Winston教授が作った会社が開発したLispのCAI(computer-assisted instruction)教材ということで、Lispの初歩から人口知能ツールの作成までを探検できるようなつくりだそうです。
また、エディタもGmacsというEmacsが用意されていたようですが、DOS時代にしてはなかなか良さそうな作りです。
他、Bit 1987年9月号、10月号とGoldhillのLisp特集があったりしますので、興味のある方は参照されると良いかと思います。

SLIME

 閑話休題。現在CLerにお馴染のSLIMEは、Common Lispの開発環境ですが、エディタという括りでいえば単にEmacsです。
2003年に開発がスタートし、今ではCommon Lisp開発ツールとしてはかなりのシェアを占めていると思います。
CL側でサーバを立てて、Emacs側と通信するという方式の為、vim等のクライアントも出ています。

大体、SLIMEの特長とされるのは、

  • シンボル名の補完
  • 関数定義の参照機能(M-.)
  • ドキュメント参照機能
  • エラーメッセージのソースコードへのオーバーレイ

位ですが、大体の所は、Lispマシン時代からの開発環境の流れを継承したものという感じです。

ただし、

  • シンボル名の補完
  • エラーメッセージのソースコードへのオーバーレイ

辺りについてはCPUパワーのお蔭なのか大分快適になっている気がします。

Light Table

2012年に颯爽と登場したLight Table。
当初Clojure向けということでしたが、その後JavaScript等にも対応し、開発が進む程なんとなく普通のエディタになってしまった感があります。
CPUパワーを要求するような見た目が格好いい機能は搭載されていますが、Lispエディタとしての本質的な改善/飛躍のようなものは無い気がしています。

まとめ

 7回にも分けて書いてみましたが、特に計画もなくその都度書いているので、まとまりが無いものになってしまいました。
1980年代位からのエディタの立ち位置は、IDEの一部としての性格が強くなるため、エディタという括りとしては、1980年代あたりで終了してしまっても良かったかなという気もしています。

大きな流れとしては、処理系+エディタというコンビがIDEとして洗練され、その洗練された文化がその後発展することもなく、若干の痕跡を残すのみで90年代のAIの冬とともに消え、再び処理系+エディタで使うのが一般的になる、という感じでしょうか。

単体のツールに焦点を絞って歴史を辿ってみるのもなかなか面白いので、そのうち今度はエディタではなく単体のツールで(トレースやステッパー等)似たようなことをやってみたいと思います。


HTML generated by 3bmd in LispWorks 7.0.0

Lispとエディタ (6)

Posted 2015-07-25 15:05:24 GMT

 今回は、1990年代のLispとエディタについてですが、AIの冬が到来し、ばたばたとLispベンダーが斃れて行く90年代です。
1980年代には、IDEの先駆けであるLispマシン環境と共に開発環境が進化したという感じですが、80年代後半から90年代初頭には、ワークステーションが普及し、Unix上のCommon Lisp処理系も出てきます。
大抵は、Symbolicsの環境を再現するようなものが多いのですが、LucidやFranzを始めとして、当時普及してきたGNU Emacsに独自のGUIツールを組み合わせた製品が多いようです。

GNU/EmacsとGUIツールの連携

Lucid CL / XLT Common Lisp Programming Environment

LucidがC++のIDEのエディタとして(GNU) Emacsを採用したという話は有名ですが、Lucid CLの開発環境も、4.0辺りからLucid Emacs+ILISP+Lucid CLという感じになったようです。

150707081001

LucidはこのEmacsと処理系の組み合わせにGUIのツールを加えて、XLTというIDEを販売していた様子。

150707082502

使ってみた感じでは、あまり洗練された感じはないですが、クラスブラウザやパッケージを切り換える謎のツールなどもあるので、色々面白くはあります。
仕組みとしては、GUIツールとEmacsが通信して連携します。

Allegro CL / Allegro Composer

LucidのXLTと似たようなもの、というかAllegro Composerの方がちょっと先行するようですが、類似のものにAllegro Composerがあります。

これは、最新のAllegro CLでも利用できますが、現行の2.0が出たのが、1996年位のようなので、ほぼ遺跡化しているような気もします。

XLTは、Lucid Emacs(XEmacs)+ILISPという感じでしたが、Allegro Composerは、Emacs(XEmacs)+ELIという構成で、同じくGUIツールとEmacsは通信して連携します。

ILISP

 上のLucid CLの話でも書きましたが、ILISPは、1990年辺りに登場し、Emacs上でCommon Lispを利用する際には広く使われたようです。
主な機能としては、

  • シンボル名の動的な補完
  • 関数引数(arglist)の表示
  • マクロ展開

等々です。
SLIMEがメジャーになる前は、主にILISPが使われていたようですが、2005年辺りにはSLIMEの方が多く使われるようになり、現在使っている人はあまりいないようです。

下記の画像は、Allegro CL 4.3とILISPを組み合せてみた例で、大体1996年位の環境の再現ですが、シンボル名の補完なども快適に行なえます。
Symbolicsを意識したTypeoutウィンドウがポップアウトして来ますが、ILISP内のドキュメントを眺めると、どうも当時は好みが分かれていたようでOFFにして使った方が良いようなことも書いてあります。

150725150229

150725150121

シンボル名の補完は初期のILISPの1990年辺りからサポートしているようなのですが、どうもこの時期には定番機能だったようで、m-v-bmultiple-value-bindに展開するような方式の補完も既にサポートされているようです。

GUIのIDE

 1990年代当時のMacOSはGUI操作がメインでUnixのごっちゃごちゃなUIに比べて操作感も統一されていますが、MCLも統一感があります。
MCLは、処理系内からMacOSの機能をフルに使えたようですが、OS/UI両面での統一感があり、かなり操作していて気持ちが良いです。

150725220636

MCLもHemlock由来のEmacsが標準のエディタですが、CLのオブジェクト指向機能を活用して書かれているようです。
この辺りもCommon Lisp的にエディタを拡張できて小気味良いですし、なんといってもエディタのカスタマイズも同じ言語でできる統一感というのは良いです。

下記は、適当にスクラッチファイルを生成して開くような簡単な例ですが、こういうのがCommon Lisp的に簡単に書けます。

#||
本当はsuperキーが使いたいが割り当てがないようなのでまあm-g n/lでもいいか 
||#

(defvar *goto-comtab* (make-comtab))

(comtab-set-key *comtab* '(:meta #\g) *goto-comtab*) (comtab-set-key *goto-comtab* #\l 'ed-open-g-file) (comtab-set-key *goto-comtab* #\n 'ed-open-next-g-file) (comtab-set-key *goto-comtab* #\p 'ed-open-previous-g-file)

(deftype gnum () '(integer 1 *))

(defun the-newest-file (dir) (let ((newest (first (sort (mapcar #'(lambda (f) (parse-integer (pathname-name f) :start 1)) dir) #'>)))) (check-type newest gnum) (make-pathname :defaults "unix:a:" :name (format nil "g~6,'0D" newest) :type "lisp")))

;; ~ (defmethod ed-open-g-file ((view fred-mixin)) (declare (ignore view)) (ed (the-newest-file (directory "Unix:a:g*.lisp"))))

(defun ensure-g-file (file) (or (probe-file file) (with-open-file (in file :if-does-not-exist :create) (declare (ignore in)))) file)

(defmethod ed-open-next-g-file ((view fred-mixin)) (let ((file (slot-value view 'ccl::my-file-name))) (ed (ensure-g-file (compute-next-g-file-name file))) ))

(defmethod ed-open-previous-g-file ((view fred-mixin)) (let ((file (slot-value view 'ccl::my-file-name))) (ed (ensure-g-file (compute-previous-g-file-name file))) ))

(defun compute-next-g-file-name (g-file) (let* ((name (pathname-name g-file)) (num (1+ (parse-integer name :start 1)))) (check-type num gnum) (make-pathname :defaults "unix:a:" :name (format nil "g~6,'0D" num) :type "lisp")))

(defun compute-previous-g-file-name (g-file) (let* ((name (pathname-name g-file)) (num (1- (parse-integer name :start 1)))) (check-type num gnum) (make-pathname :defaults "unix:a:" :name (format nil "g~6,'0D" num) :type "lisp")))

;; *EOF*

他、GUIをメインにしたIDEを販売していたベンダーとしては、HarlequinのLispWorksがあるようです。
これは紆余曲折あって現在のLispWorksに繋がります。

1990年代後半

 Windows 3.1あたりからPCの利用が増え始め、Windows 95のブレイクによって一気にPCが普及しますが、LispベンダーもWindowsに力を入れ始めます。
当時のWindowsプラットフォームでは、UnixのようにエディタにはGNU Emacsを使ってしまえ、ということもできなかった為かGUIのIDEが登場してきます。
操作感としては、Emacsっぽくもできますが、デフォルトではPC操作に馴れ親しんだ人向けという感じです。

Allegro CL 5.0のWindows版あたりでは、当時流行っていたRADツール的な面が強調されているようにも見えます。

まとめ

 かなりごちゃごちゃとした1990年代ですが、SymbolicsなどのLispマシンで培ってきた文化は、Unixワークステーションのようないまいち統合されていない環境では上手く継承されず、部品ごとにバラバラにしたものを、エディタ+処理系のように組み合せて使うという現在主流の使い方に落ち着いてしまったようです。

そんな流れの中ではMCLがかなり良い感じでOS/GUIに統合されていたように思えます。
Norvig先生が、2001年に開発環境のレビューをしていますが、この中でもMCLはベストのIDEと評価されています。

これを読んだ時には、本当かいなと思っていましたが、実際試してみると、確かにSymbolicsの環境に匹敵する統一感はあるように思います。
しかし、その後MacがMacOSXに移行した位の時期にはMCL開発も鈍っていてCarbon対応したものの継ぎ接ぎ感があり、Digitoolも最終版のMCL 5.2を2007年にオープンソース化して開発もストップしてしまいます。

次回は、ほぼ現在と同じ2000年代で最後にしたいと思います。といってもあまり書くことがない気がしますが…。


HTML generated by 3bmd in LispWorks 7.0.0

LispWorks 7購入への道(3) ─ Java連携を試す

Posted 2015-07-20 13:50:09 GMT

 Allegro CLでは、結構前からjLinkerという機能がありCommon LispとJavaが連携できたりしましたが、LispWorksは最新の7から連携機能が付いたようです。

普段Javaを呼んだりすることはあまりありませんが、折角なのでどんなものか試してみることにしました。

下準備

LispWorks Java interfaceを利用するには、Linuxの場合、libjvm.soが利用できるようになっている必要があるようです。
LD_LIBRARY_PATHで設定するか、ldconfigで設定することになるかと思います。
64bit Debian GNU/Linuxでは、下記のパスを登録すればよいようでした。

/usr/lib/jvm/java-7-openjdk-amd64/jre/lib/amd64/server/

LispWorksへパッチの適用

 このJava連携機能ですが、ファイルの同梱漏れがあったようで、lispcalls.jarをサイトからダウンロードして適切な場所に設置する必があります。

(2015-07-20日現在、最新のインストーラからインストールを実行してもlispcalls.jarは導入されません。)

Javaを呼んでみる

 利用にはモジュールをロードして初期化という流れのようです。 下記は、joda-timeとicuを呼んでみている例と、入門サイトのちょっとした例を書き換えてみた例です。

(require "java-interface")

(lw-ji:init-java-interface :jvm-library-path T :java-class-path '("/var/tmp/joda-time-2.8.1/joda-time-2.8.1.jar" "/usr/share/java/com.ibm.icu-4.2.1.1.jar"))

(lw-ji:import-java-class-definitions "org.joda.time.DateTime") (lw-ji:import-java-class-definitions "com.ibm.icu.text.Normalizer")

(let ((date (|org.joda.time|:datetime.new))) (list (|org.joda.time|:datetime.getyear date) (|org.joda.time|:datetime.getmonthofyear date) (|org.joda.time|:datetime.getdayofmonth date) (|org.joda.time|:datetime.gethourofday date) (|org.joda.time|:datetime.getminuteofhour date) (|org.joda.time|:datetime.getsecondofminute date))) ;=> (2015 7 20 22 11 23)

(defun normalize-string (s) (|com.ibm.icu.text|:normalizer.normalize s (lw-ji:read-java-field "com.ibm.icu.text.Normalizer.NFKC")))

(normalize-string "ABCDEFG12345アイウエオABCDEFG12345アイウエオ") ;=> "ABCDEFG12345アイウエオABCDEFG12345アイウエオ"

なお、lw-ji:write-java-class-definitions-to-fileを使うとJavaのクラス定義が書き出せて、後でこのファイルをロードすることで lw-ji:import-java-class-definitionsの手間を省くことも可能なようです。

(lw-ji:write-java-class-definitions-to-file "org.joda.time.DateTime" "/tmp/joda-datetime.lisp")
(lw-ji:write-java-class-definitions-to-file "com.ibm.icu.text.Normalizer" "/tmp/icu.lisp")

(load (compile-file "/tmp/icu.lisp)") ...

JavaDrive: テキストをファイルに書き込む の例をlw-jiで

(macrolet ((jimport (&rest classes)
             `(progn
                ,@(mapcar (lambda (c)
                            `(lw-ji:import-java-class-definitions ,c))
                          classes))))
  (jimport "java.io.File"
           "java.io.FileWriter"
           "java.io.BufferedWriter"
           "java.io.PrintWriter"
           "java.io.IOException"))

(defun check-before-wite-file (file) (and (|java.io|:file.exists file) (|java.io|:file.canwrite file)))

(let* ((filename "/tmp/text.txt") (file (|java.io|:file.new filename))) (if (check-before-wite-file file) (let ((pw (|java.io|:printwriter.new (|java.io|:bufferedwriter.new (|java.io|:filewriter.new file))))) (unwind-protect (flet ((output (msg) (|java.io|:printwriter.println pw msg))) (output "今日の最高気温は") (output 10) (output "度です")) (|java.io|:printwriter.close pw))) (error "ファイルに書き込めません")) (hcl:file-string filename :external-format :utf-8)) ;=> "今日の最高気温は ; 10 ; 度です ; "

まとめ

Javaが呼べるCommon Lisp処理系というと、Allegro CLのjLinkerの他にJVMを利用した処理系であるABCLがあります。
API的には、jLinkerとABCLは似ている所がありますが、LispWorks Java Interfaceは、これらとはちょっと違った雰囲気になっているようです。


HTML generated by 3bmd in LispWorks 7.0.0

LispWorks 7購入への道(2) ─ StumpWMをLWで

Posted 2015-07-19 14:07:05 GMT

 自分は、ウィンドウマネージャーは、Common Lispで実装されたウィンドウマネージャーであるStumpWMを利用していますが、現在処理系はSBCLを利用してます。
確かStumpWMのメーリングリストでLispWorksを使って動かしたという人がいたと思ったので、多分LispWorksでも動くんだろうと思って試してみました。

試してみた結果ですが、CLXがLispWorks 7でコンパイルする時に対応外のプラットフォームとしてエラーにしますが、対応のプラットフォームとしてLispWorks 7が入っていないだけなので、追加してやればコンパイルも通ります。

実行可能ファイルの作成

StumpWMの実行可能ファイルは、LispWorksの場合、save-imageで作成可能です。
swankも起動しておきたいのでこんな感じのファイルを書きました。

;;; make-stumpwm.lisp

(ql:quickload :swank)

(ql:quickload :stumpwm)

...

(defun run-stumpwm () (stumpwm:stumpwm) (lw:quit :status 0 :ignore-errors-p T))

(defun run-swank () (swank:create-server :port 7777 :dont-close T))

(pushnew '("StumpWM" (:priority 60000000 :restart-action :continue) run-stumpwm) mp:*initial-processes*)

(pushnew '("Swank 7777" (:priority 60000005 :restart-action :continue) run-swank) mp:*initial-processes*)

(hcl:save-image "/tmp/lw-stumpwm" :console t :multiprocessing t :environment nil)

これを、

$ lispworks-7-0-0-amd64-linux -init - -siteinit - -build make-stumpwm.lisp

みたいにして、StumpWMのイメージを作成できます。

まとめ

StumpWMをLispWorks 7で動かしてみました。
現状のStumpWMでは日本語入力に難がありますが、LispWorksのcapiだとダイアログを作るのが簡単なので組み合わせて欠点を補えそうです。

(stumpwm:defcommand ohayo () ()
  (capi:contain (make-instance 'capi:display-pane :text "おはよう日本")))

パソコンを使っている時間とほぼ同じ時間だけ起動しているStumpWMですが、これがLispWorks 7になれば、LispWorksの利用時間だけは長くできます。


HTML generated by 3bmd in LispWorks 7.0.0

LispWorks 7購入への道(1)

Posted 2015-07-19 04:30:42 GMT

 LispWorks 7は今年の5月に発売になりましたが、今回新しくHobbyist EditionとHobbyistDV Editionというプランが用意されました。
お値段は、32/64bit版共にHobbyist版方は$750、HobbyistDV版は$1500ですが、以前まで64bit版は$4500のEnterprise版しかなかったので、64bitプラットフォームを利用している自分にとっては嬉しい所。

2ヶ月位逡巡していましたが、やっぱりHobbyist版欲しいということで購入を決意。
決意しましたが、しかし、評価ライセンスで1ヶ月使えるということなので、念の為、評価ライセンスを申し込むことにしました。

申し込んだライセンスは、購入予定のHobbyistより一つ上のHobbyistDVです。
DVと無印の違いですが、単体アプリの実行可能ファイルを出せるか出せないか、のようです。
といってもHobbyistDVで作成したアプリを製品として配布可能なライセンスではありませんので、配布にはまた別のライセンスが必要になるようです。

評価ライセンスの申し込み

評価ライセンスの申し込みですが、下記のページに書いてあるようにメールで申し込みます。

自分の場合、2、3時間後に評価用のライセンスキーと処理系のダウンロードリンクが送られてきました。

セットアップ

セットアップは簡単で、Linux版の場合、シェルスクリプトを実行するだけです。

動作確認

SLIMEとの連携

さて動作確認ですが、最新のSLIMEでも問題なく動きます。
SLIMEでLispWorksを使っている人が少ないようなのでSBCLに比べると色々とサポートは薄いですが、この辺りを直してSLIMEのプロジェクトにパッチを送るのも趣味プログラミングの課題としては好いでしょう。
ぱっと見た感じでは、

  • コンパイルの警告/エラーでのオーバーレイが表示される場所が適切でない場合がある。
  • M-.して飛んで行く位置がたまに違う

位の所です。

LispWorksのIDE

エディタ

IDEは全般的に好い感じなのですが、以前からプラットフォームそれぞれで日本語入力の問題がありました。
Linux版は、6よりGTKになり、処理系もUTF-8に対応しているので、その辺りは改善されたのですが、さて7はどうかと試してみたところ、自分が使っているuim-ximとは相性が悪いらしく、1ストロークで入力する「あ、い、う、え、お」辺りは二回目以降の入力が無視され入力されず。

6の頃はこんなことは無かったので、ちょっと調べてみる必要がありそうです。
バグ報告しても好い気はしますが、Linuxでuim-ximでskkの組み合わせ特有なのかどうなのか、もうちょっと切り分ける必要はありそうです。

しかし、SLIMEから、

(capi:contain
 (make-instance 'capi:editor-pane
                :text "おはよう日本"
                :buffer-name :temp))

して生成したeditor-paneではそういう妙な現象もなく、問題が生じているLispWorks IDE上から生成したものは親の症状を継承するらしいことが判明。
そうなると何らかの環境の違いが影響している可能性が高いので、LispWorksのエディタも設定次第では問題なく使えるかもしれません。

まとめ

以上、LispWorks 7 Linux 64bit版を触ってみた最初の印象でした。
LispWorksはIDEが良くできている印象ですが、中心となるエディタでは日本語も快適に入力したいなあという感じです。
環境依存の問題っぽくもあるので、問題を切り分けてみたいと思っています。


HTML generated by 3bmd in LispWorks 7.0.0

Medleyを使ってみよう(2)

Posted 2015-07-15 05:06:39 GMT

 Medleyを使ってみようシリーズの第二回、前回は4年半前でした。
過去のmedley関係の記事は、こんな感じです。

Medleyとは

Medleyとは、Interlisp-Dが仮想マシン化したものです。
LinuxやIRIX(MIPS)、Solaris(SPARC)等で動くようですが、自分は、古いLinuxで動かしています。

Metaキーはいずこ

Medleyを触って早10年位になります。特に何もしてないのですが、Metaキーがどこに割り当てられているかが分からず、エディタでは苦労して入力していました。
便利機能の殆どがMetaキーに割り当てられていて、Metaキーが使えないとマウスでポチポチやって文字を入力する位しかないのです。
これではいかんと思い、MetaキーがXではどこに割り当てられることになるのか探ってみたところMedleyではAlt_Lに割り当てられることが判りました。

xmodmapで

clear    mod1
keycode  キー番号 = Alt_L
add     mod1    = Alt_L

のようにすればOKですが、自分は、左Metaキーには、Meta_Lを割り当てているため、Alt_Lを有効にするために、Xnestで別ディスプレイを開いて設定しています。
vncでできると良いのですが、どうもAlt_Lがどんどん別の場所にずれて行くという謎現象が解決できず。

SEditのコマンド

SEditでのカーソル移動と範囲選択

カーソルの移動は基本的にマウスでしかできません。キー操作も用意されていそうなものですがマニュアルを眺めても見付けられず…。
選択ですが、左クリックをすると範囲が外側に伸びてゆきます。
左クリックだと1つの式しか選択できないのですが、複数を選択したい場合は、先頭要素を真ん中クリックで選択し、最後尾を右クリックすると、箱状に範囲が選択されます。

SEditでの基本S式編集コマンド

さて、Interlisp-Dの構造エディタのSEditのコマンドですが、主な所ではこんな感じになっています。

Delete、c-h 後一文字を削除
c-w 選択を削除
m-u アンドゥ
m-r リドゥ
m-f 検索
c-m-f 後へ検索
m-s 置換
c-m-s 選択を削除
c-m-; 選択をコメントアウト
m-o 別エディタで編集
m-e 式をeval
m-x 式をマクロ展開して元の式と置き換え
m-/ 所謂スプライシング “(x y z) ⇒ x y z”
m-i インスペクト
m-j 範囲を結合(シンボルの場合は、シンボル名が結合、リスト、文字列等、色々結合可能)
m-( 括弧で囲む
m-) 括弧で囲む。カーソルは後へ
m-, 選択に,を付ける
m-@ 選択に,@を付ける
m-. 選択に,.を付ける
m-' 選択に'を付ける
m-` 選択に`を付ける
c-c コンパイル
c-x 評価
c-m-c コンパイルしてエディタを閉じる
c-m-x 評価してエディタを閉じる

選択となっているのは、1つ以上の要素を編集対象としています。

編集する上で便利なのは、さくさく削除するc-wと、検索(選択される)&削除 or 置換 でしょうか。
カーソル移動がダルいのでm-fで移動するのもありだと思います。

別エディタを開くm-oについては、Emacsでいうとm-.のような感覚です。

対話的に書く

ちょっと書いては評価スタイルの場合ですが、SEditだとエディタの画面1つには1式しか表示されないので、リスナーと行ったり来たりになります。
redofixuseがあるので、そこそこ動作確認もできますが、(sedit:sedit '(foo 1 2 3))や、(sedit:sedit '(macroexpand '(mac x y z)))として別エディタを開いて、この式をm-eする方が楽な気もします。

まとめ

久々にMedleyのことを書いてみました。
Interlisp-Dの環境も大体使える位まで把握したい所です。


HTML generated by 3bmd in SBCL 1.2.13

Common Lispは大文字と小文字を区別しないという誤解

Posted 2015-07-14 08:03:46 GMT

Common Lispは大文字と小文字を区別しないという誤解があります。
もちろんそんなことはないので、色々実際の仕様を説明してみるのですが、「なるほど分かった、でも、Common Lispは大文字と小文字を区別するようにした方が良いよね」という、ねじ式のような反応が多いです。

説明を繰り返すなかで、私も段々と諦めてきましたが、せめて、「区別しない」のではなく、「Common Lispはデフォルトでシンボルを大文字に畳み込む」という理解までは持っていきたいと思ったのでこれを書く次第です。

技術的な話なのか

以下、話を判りやすくするために、「大文字と小文字を区別するべき」という認識を持つ人をCS派とします。

まず、技術的には、Common Lispは大文字と小文字は区別します。
シンボルは、読み込み時に大文字に畳み込まれるのがデフォルトですが、文字列リテラルは畳み込まれませんし、シンボルは、|FooBarBaz|のようにエスケープすれば畳み込みをエスケープ可能です。

しかし、この「大文字に畳み込む」ということと、エスケープ可能であることがCS派にはなかなか理解されず、ねじ式のような光景が繰り広げられるのです。

また、大文字と小文字が区別されないとは、文字列"Foo Bar Baz""FOO BAR BAZ"になっちゃうということですか?と訊いてみるに、「はは、さすがにそれはないです」というような返答がCS派からは多いです。
私からすれば想定している状況と言葉の表現に一貫性が無く、逆に理解が難しい。

CS派のいう大文字と小文字を区別する/しないとはなんなのか

端的にいうとソースコードの大文字と小文字の記述をそのまま保存した状態が望ましいと考えていて、そうすればすべて解決すると考えているのだと思います。

畳み込みのメリット/デメリット

まず、畳み込まないメリットですが、FFI等で他の言語の呼出しをする時にFooBarFunction|FooBarFunction|などと書かなくて良い点です。
また、Rubyのように定数やクラス名の印という使い方も可能でしょう。
CS派はこういうメリットを活かした書き方をしたいのかもしれないです。

畳み込むメリットは、foo-bar-functionFOO-BAR-Functionと書いてもFoo-Bar-Functionと書いても構わないので大文字小文字の違いによるミスは発生しないですし、記述で色々遊べます。
これに馴れてしまうと、シンボル名のどこが大文字でどこが小文字だったかをコーディング規約で決めたり暗記したりするのが無駄に思えます。

シンボル名には-等記号も普通に使えますし、大文字小文字で区切りを付ける必要性もあまりありません。
また、どうしてもFooBarと書きたければ書けば良いです。
もちろんシンボル名の文字列は"FOOBAR"になるのですがソースコード上に畳み込まれた表現が現われる必要はないです。

さらにこだわるなら、|FooBar|と書きましょう。

時代的な話なのか

大文字と小文字を区別できなかった端末を使ったことがある人には、「時代の流れとしてcase-sensitiveになるべき」という主張をする人がいます。
繰り返しになりますが、Common Lispは、case-sensitiveなんです。

区別できなかった端末を使っていた経験があるから、そんな感覚がある訳ですが、今の若者からすれば、なんで大文字に正規化されるの?位のもので、つまり、Common Lispが古いというよりその人が生きた時代が古いのです。

ちなみに、pdp-1はASCIIではなくFIO-DECを採用していたため、pdp-1 lispは、Lispの歴史のほぼ最初期の1964年あたりから大文字と小文字を区別していました。
その後、安価な端末を使うことになり、大文字しかサポートしない端末に合せることになり、MACLISPでは長らく大文字に畳み込むことになります。
つまり、端末が大文字小文字を区別するように進化していったというより、世の中のコストダウンの流れに合せたということなのです。

一方、1970年代になるとINTERLISP方面では、大文字への畳み込みをやめます。
ここで面白いのが、Allegro CLのmlispとは違って標準のシンボル名は大文字のままにしたということです。
そうなると、小文字をデフォルトとする端末では、一々shiftを押すことになるのですが、ここでDWIMの修正機能が活躍し、入力を適切に大文字に変換してくれていて、ある意味mlisp(modern lisp)よりモダンでした。

今のCommon Lispで読み込みを:preserveにするとどうなるのか

Common Lispで読み込みを:preserveにすれば、畳み込みはしません。
しかし、INTERLISPの話でも触れましたが、標準関数は現状大文字なのです。

つまり、

(DEFUN fib (n)
  (IF (< n 2)
      n
      (+ (fib (1- n))
         (fib (- n 2)))))

のように記述する必要があります。
恐らく、これが「大文字と小文字を区別する」ことの望ましい結果とはCS派は考えていないでしょう。

話はちょっと変わりますが、FFI等で、

(defun foo (x y)
  (|fooBarFunction| x y))

と書くのが面倒という場合は、:preserveにして

(DEFUN FOO (x y)
  (fooBarFunction x y))

を読ませても良いということでもありますね。

結局どうなれば良いのか

大文字に畳み込まれるのがダサい

これまでCS派の主張を様々と耳にして考えてみましたが、最終的な私の予想としては、CS派が言いたかったのは、「大文字小文字を区別するべき」という話ではなく、「大文字に畳み込まれるのがダサい」ということです。
これは自分もダサいと思います。
そういう話なら納得できる。
多分、技術的な話ではないので、技術的に説明しても無駄なのです。

飽く迄想像ですが、小文字に畳み込まれていたら、「小文字に正規化される」という認識で、それを回避するにはエスケープ記号を使う、位の認識になっていたと思うのですが、大文字になってしまうので、違和感や時代感が噴出してくるのではないでしょうか。

小文字に畳み込めば良い

新しいCommon Lispの仕様がもし提案されて、リード時に畳み込みをするのならば、小文字に畳み込まれると良いのではないでしょうか。
そして標準関数も小文字で構成します。
過去の処理系のイメージは共有できないと思いますが、まずそういうこともしないでしょうし、ソースコードの互換性は維持されるので問題ないと思います。

次善として、畳み込みのメリットが不要ということであれば、Allegro CLのmlispで標準関数が小文字で構成され、:preserveで読まれる+過去との互換性確保のためのin-case-modeのような仕組みを付けることでしょう。

まとめ

以上、Common Lispは大文字と小文字を区別しないという誤解を考えてみました。
Common Lispはシンボルの大文字と小文字を区別するんです。
デフォルトで大文字に畳み込むのはダサいです。

技術的な話ではない、と結論しましたが、何か技術的なことがあれば、ご意見を伺いたいと思っています。


HTML generated by 3bmd in International Allegro CL Enterprise Edition 8.2 [64-bit Linux (x86-64)] (Apr 26, 2015 8:54)

Allegro CL/mlispとin-case-mode

Posted 2015-07-14 05:53:46 GMT

Allegro CLにはmlispというモードがありますが、これは、ANSI CLの規格(以下ANSと略)とは異った仕様にすることで利用者の便宜を図るというものです。
具体的なANSとの違いは、

  • common-lispパッケージのシンボル名は全部小文字で構成されている
  • リーダーの読み取りモードは、:preserveで標準の:upcaseと異なり大文字に畳み込まない

というのが主な所です。
この仕様についてCommon Lispの大文字と小文字を区別しない所を改善した、と思っている人が割といますが、端的にいえばANSの仕様の勘違いをしています。
主な勘違いとは、

  • ANSでのcommon-lispパッケージのシンボル名は全部大文字で構成されていることを知らない
  • ANSでも大文字小文字は区別するがデフォルトでは、:upcaseとなっていて大文字に畳み込む。:preserve にすればmlispと同様になる。

というところです。
読み込みについては:preserveにすれば良いので簡単に解決できますが、clパッケージが全部小文字というのが厄介な所です。
一見エイリアスを作って解決に思えますが、スペシャル変数はエイリアスを作ることができないので、規格の範囲で対処するのは恐らく無理だと思います。
リーダーマクロを使う方法も試してみたことはありますが(**で囲むと大文字に変換する)、やはり無理があるという印象です。
ちなみに、Allegro CLの場合ですが、実行ファイルをmlispと、alisp(ANSモード)とに分けることによって対応しています。

こんなmlispとANSの関係ですが、ANS尊守の人からは、規格外のもの広めようとするなどFranzはけしからん、という声もあったりします。
自分もどちらかといえば、ANSに準拠していて欲しいのでmlispの利用は回避していました。

Allegro CLのin-case-mode

そんなmlispなのですが、ふとマニュアルを眺めていた所、in-case-modeというものを見付けました。

Allegro CL 8.2から標準搭載のようですが、それまでは読み取りモードを手動で設定していたのを、in-package的に簡単に指定できるようにしたもののようです。
これは、ソースファイルにも、faslファイルにも対応しているものですが、動作を確認してみます。

alispでコンパイルしたものをmlispで読む

互換性の問題で云えば、alispでコンパイルしたものをmlispで読めれば全て解決と思われます。
こんなファイルを作成して

  • am.lisp

(defpackage "AM" (:use :cl))

(cl:in-package "AM")

(defun barp (x) (eq 'Bar x))

(defun bazp (x) (eq '|Baz| x))

alispでコンパイルし、mlispで(in-case-mode :common)で読み込みます。

(compile-file "am.lisp") ;alisp

(progn
  (in-case-mode :common)
  (load "am.fasl"))

(am::barp 'am::bar) ;=> t (am::bazp 'am::|Baz|) ;=> t ;; おまけ (am::bazp 'am::Baz) ;=> t

ANSモードでの意図はそのまま保存できているようです。
ソースコードをコンパイルしないで読み込んでも(in-case-mode :common)なら意図通りです。

mlispでコンパイルしたものをalispで読む

同様に、こっちは畳み込みがないので余裕でOKかと思いきや、

  • ma.lisp

(defpackage "MA" (:use :cl))

(cl:in-package "MA")

(defun barp (x) (eq 'Bar x))

(defun bazp (x) (eq '|Baz| x))

(compile-file "ma.lisp") ;mlisp

(load "ma.fasl")

(ma::barp 'ma::bar) ;=> t (ma::bazp 'ma::|Baz|) ;=> nil (ma::bazp 'ma::baz) ;=> t

エスケープが無視されてしまうようです。
まあ、mlispで、FooBar|FooBar|と書く人もいなさそうなので致し方ないのでしょうか。

まとめ

以上、mlispでのin-case-modeについて書いてみました。

要約すると、ANS準拠派の人は、mlispのことは一切考えなくても良いということです。
また、mlispの人も、Quicklispに収録のライブラリでもソースコードを手動で修正したりせずに、ANSで書いた人の意図通りに読み込めると思われます。
(具体的には、quicklisp/asdfを利用しているなら、コンパイル/ロード時に(in-case-mode :common)のフックが掛かるようにすればOK)

ちなみに、mlisp用に手動でちょこちょこ直すという話は、割合と世界的なものな気はします。
例えば、defpackageでのパッケージ名を#:fooのように書くのはmlispフレンドリーになるから良い、というようなものですが、mlisp側で吸収する仕組みがある以上、ANSで書いてる人は、そんなことは気にする必要はなく、この豆知識は放棄した方が良いと思います。

また、mlispはけしからん、という話もFranzが頑に対応していないなら兎も角、mlisp側に吸収する仕組みを用意しているからには、規格から外れた方が遵守の方に合せるという姿勢はあるように思えます。


HTML generated by 3bmd in International Allegro CL Enterprise Edition 8.2 [64-bit Linux (x86-64)] (Apr 26, 2015 8:54)

Lispとエディタ (5)

Posted 2015-07-12 01:48:33 GMT

延々と続いていますが、今回は、1980年代のLispとエディタについてです。

さて、1980年代位になると単体のエディタが注目されることも少なくなり、代わりに開発環境というものが追求されるようになります。
ということで、Lispとエディタというテーマでは、この辺りで一段落してしまう、という印象です。

1980年代前半位までの開発環境については、当時の状況を纏めた、Interactive Programming Environments / David R. Barstow, Howard E. Shrobe, Erik Sandewallという本が出ていますので、興味のある方は読んでみると面白いと思います。
ソフトウェア開発支援環境―UNIXからAIアプローチまでという和訳も出ているようです。

  • 言語か環境か
  • ファイル指向 vs イメージ指向

辺りのトピックは、1980年代前半に良く考察されていたらしいことが分かります。

構造エディタ vs 汎用エディタ

1980年代前半位までは、構造エディタ vs 汎用エディタで競っていたことがあったようですが、後から振り返ってみるとこの辺りで汎用エディタに軍配が挙がってしまったようです。
構造エディタも汎用エディタでできることは可能だった筈ですが、特化したエディタは特化した用途以外には使いづらい、という印象が勝ってしまったのでしょうか。

上記の、Interactive Programming Environmentsの中のSandewall氏の論文「Programming in an Interactive Environment: the “LISP Experiments”(PDF)」では構造エディタと汎用エディタを比較したりしていますが、これに対してrmsがEmacsの立場から反論したりしています。
残念ながらPDFで読める版にはrmsの反論は載っていませんが、主な反論内容は、構造エディタ推しの内容に納得できないというものです。
Sandewall氏からの返答も載っていますが、そんなことはないよというもので、rmsの指摘も論文中に挙げているものが殆どだとしています。

まあ、今からすると、こういう戦いもあったんだなという話ですが、Emacsの方もS式編集では、構造エディタ的な動きもするわけで、RISC vs CISCのように、CISCだったIntel CPUもRISC化してしまった話に近いものを感じます。

Lispの開発環境とエディタ

1984年にCommon Lispが決まり、Common Lispは商用化の道を歩み出しますが、当時は現在のようにソフトウェアがインターネットでなんでも配布されるような時代ではないので、開発ベンダーがパッケージを売るという形態です。

Common Lisp 開発環境でのエディタ

ベンダーごとに他と差別化を図るためにそれぞれ特色があるのですが、Common Lisp単体で販売されるということは、ほぼ無かったようです。

大抵、開発ツールが付いてくるのですが、品揃えを眺めてみると、やはり当時先端を走っていたLispマシンを追い掛けるようなものが多いようです。

メインとなるのは、やはりエディタですが、大抵Common Lispで実装されたEmacsが付いてきます。
一覧にするとこんな感じです。

ベンダー エディタ
Symbolics/LMI/TI Zmacs
Spice Lisp Hemlock
VAX LISP VAX LISP Editor
NIL Steve
Lucid CL Helix
MCL Fred
Allegro CL Emacs
TAO/ELIS Zen
poplog VED

それぞれどんな感じかというと、

Symbolics/LMI/TI: Zmacs

ZmacsはZWEIとほぼ同じなのですが、Symbolicsが商用化にあたって名前をZmacsとしたようです。
といっても競合のLMIもTIもZmacsという名前なのが不思議な所。
今のSLIMEとほとんど変わらない感じです。

Spice Lisp: Hemlock

Hemlockは今でもCommon Lispで実装されたEmacsとして、そこそこ知られていますが、元々はSpiceプロジェクトで良く使われたエディタのようです。
Spiceプロジェクトは、Altoのような個人用コンピュータ環境についての研究だったようですが、プロジェクトで使われたPARQも、プロジェクトの想定として汎用アーキテクチャの採用を指向していた割には、プログラマブルなマイクロコードを持つマシンだったようなので殆どLispマシンのような感じになっています。
XGAからSXGA位のビットマップディスプレイにGUIの環境というものですが、Hemlockも大体Zmacsという感じです。

VAX LISP: VAX LISP Editor

VAX LISPはウィンドウシステムで使うことも想定されていますが、どうもターミナルで使う方をメインに考えられていたようです。 VAX LISP Editorは、汎用のエディタですが、LISPモードがあって、Common Lispからは、(ed 'foo)で呼び出せ、エディタから式を評価し、結果をエコーバックすることも可能なのでエディタ画面から切り換えずに結果を確認しつつ書いて行くことも可能。
式単位でも移動等もサポートしていて、EmacsのLISPモード的なことは大体可能です。
キーバインドもLispからカスタマイズすることが可能だったのでEmacsのキーバインドにすることも不可能ではない感じです。

NIL: Steve

Common Lisp(NIL)+Flavorsで実装されたEmacsです。
詳細は不明ですが、LMI Lambdaのソースコードに残されたSteveのソースを眺める限りは大体他と似た感じなのではないかと思います(C-M-cで式をコンパイル等々)
ちなみに、NILEというものあるらしいです。

Lucid CL: Helix

Helixは、Lucid社がカスタマイズしたHemlockで、ウィンドウシステムとターミナルで利用可能です。
これも試してみた所では、他のLispで実装されたEmacsと変わりないと思います。
1990年位から、Common Lisp+Emacs(Lucid Emacs/XEmacs)の組み合わせに移行してゆきます。

MCL: Fred

Fredも元々はHemlockですが、MacintoshのGUI環境に上手く統合されています。 使い勝手は他のLispで実装されたEmacsと似た感じです。

Allegro CL: Emacs

現在のAllegro CLの始まりは、1986年発売のTektornix 4400シリーズ(Smalltalkで有名なマシン)向けのTek Common Lisp(Extended Common Lisp)です。
exclとして今でもパッケージ名に形跡を残していたりしますが、Tektronix 4400シリーズのカタログを眺める限りでは、当初はUnipress Emacs(所謂Gosling Emacs)と連携して使えたようです。
GNU Emacsが登場すると、GNU Emacsとの連携を強化する方向になり、現在のELIにつながります。

TAO/ELIS: Zen

Zenは、TAO/ELISで記述されたEmacsで、全面的にTAOのオブジェクト指向な機能を使うことをテーマに製作されたもののようです。
また、Lispマシンのメリットを活かす試みの一環で、エディタ自体を部品化し、他から呼び出して使うことも想定していたとのこと。
Emacs利用者にはお馴染のSKKは、Zen上のKanzenから影響を受けて作られたものとのことです。

以上、なんとなくですが、1980年代のCommon Lispには大抵Common Lispで実装されたEmacsが付いてきていた、という感覚がというのが分かるのではないでしょうか。

EmacsとLisp

GNU Emacsは拡張言語にEmacs Lispを搭載しているので、Lispの文脈で語られることは多く、Lispが書けないとEmacsは使えないといわれたりする程ですが、個人的には、EmacsというエディタはTECOの実装の時点でほぼ機能は完成していることからして、拡張言語にLispを使ったことによるEmacsのLisp化/Lispからの影響、というのはあまりないように思います。

しかし、Lispで実装されたエディタは圧倒的にEmacsが多いというのはあるので、Lispでエディタを作るとEmacsを作ってしまうことが多い、というのは歴史的な事実ではあるようです。
つまり、Emacsが好きな人がLispを好きだとは限らないが、Lispの人は大抵Emacsが好き、ということですが、これは今でもなんとなく続いているような気がします。

Franz Lisp と vi

さて、Emacsは良いとして、vi派はどうしていたのだろうというと、BSD Unix が主戦場だったFranz Lispでのメインエディタだったようです。
viの%などもこの時期に加えられたコマンドとのことですが、詳細は不明です。
Common Lispに、(ed)があるように、(vi)や、(ex)という関数があり、Lispからエディタを呼べたようです。
Franz Lispのコードを眺めれば、viでLispを編集するとどういう感じになるのか、は窺い知ることはできるのかもしれません。

INTERLISP方面

Interlisp方面も1980年代にはLispの専用マシンの方向に進化して、Interlisp-Dとなります。
Interlisp-Dでも構造エディタが使われていますが、以前よりイメージ指向の環境と統合されています。
BBN-LISPからの流れを受け継いでInterlisp-DでもLispコードが定義されたファイルを開くという感覚は薄く、(edit ...)を実行するとエディタの窓が開くので関数定義の記述を編集する、という方式です。
仮想Interlisp-D環境で、Lispの関数を編集している動画があるので、これを眺めると、どういう感じかが大体分かると思います。

この動画にもありますが、インデントのことはエディタに完全にお任せでどんどん書いていく、という感覚はなかなか気持ち良いです。

基本的に整形はシステムまかせなので、整形についてあれこれ気にしなくなる傾向は強いと思います。

まとめ

 1980年代は開発環境が急激に進歩している感じではあるのですが、開発環境のことを書いていると話が終わらないのでエディタに絞りました。
開発環境については別途単体機能ごとに歴史的な発展を眺めてみたいと思っています。

次は、ほぼ現状と変わらない感じですが、1990年代を眺めてみたいと思います。


HTML generated by 3bmd in SBCL 1.2.13

Older entries (1952 remaining)