Hatena::Groupcadr

わだばLisperになる このページをアンテナに追加 RSSフィード

2004 | 12 |
2005 | 01 | 02 | 07 | 10 | 11 |
2006 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2007 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2008 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2009 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2010 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2011 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 11 |

2010-07-31

(43)Object - Oriented Programming in Lisp(1983)

| 21:03 | (43)Object - Oriented Programming in Lisp(1983) - わだばLisperになる を含むブックマーク はてなブックマーク - (43)Object - Oriented Programming in Lisp(1983) - わだばLisperになる

TAO関係の論文を漁っておりますが、今回は、

です。

論文にTAOの名前がないので見落して抜かしてしまっていましたが、TAOのオブジェクト指向プログラミング方面について書かれています。

TAOでは、レシーバとメッセージの書き方から

[3 + 3]

のように中置で書けるというお馴染の解説から具体的な実装戦略などが詳細に解説されています。

これまで読んだところでは、TAOのオブジェクト指向プログラミングについては、これが一番詳しい気がします。

また、後半はZetalisp等のFlavorsや、Interlisp-DのLoops等との比較もあります。

文中でも少しだけ言及されていますが

(3 + 3)

と書けるだけでなく、TAO

f(x)
;; (f x)と同じ

のようにも書けるようです。

この辺りについては、

no title

に詳しく解説があります。

2010-07-30

(42)TAOにおける代入計算機構(1985)

| 23:47 | (42)TAOにおける代入計算機構(1985) - わだばLisperになる を含むブックマーク はてなブックマーク - (42)TAOにおける代入計算機構(1985) - わだばLisperになる

TAO関係の論文を漁っておりますが、今回は、

です。

8/7〜9日のELIS復活祭まで一通りの論文を読み終えておこうと思っていたのですが、まったりしているうちにあと1週間位しかなくなってしまいました。

あと、十本位あるのですが…。

とりあえず、90年代以降は、TAO/ELISではなく後継のTAO/SILENTになるようなのでTAO/ELIS時代は眺めておきたいところ。

本文は、TAOのコードの見た目の特徴にもなっている、代入機構(!や!!)についてです。

ちなみに!や!!より前には、:や、::で表現されていたようで、!に切り替わったのは、この論文の後位のようです。

この代入の機構は、CLでいえば、(setf (car foo) :foo)のようなところを、TAOだと(:(car foo) :foo)と書けます。

CLの場合は、マクロで実現していますが、TAOでは、これをマイクロプログラミングレベルで実現しているとのこと。

読み出してきた値の保持には専用のレジスタが使われます。

TAOだとsetqもマクロで(:x 'foo)の方がよりプリミティブになるとのこと。

(:x 123)

というのは元より

(defvar y (list 1 2 3 4))
(defvar n 2)

(:(member n y) (+ n 1))
;⇒ (1 3 3 4)

(defvar flip nil)
(defvar flop 42)
(defvar x (cons 1 2))

(:(cond ((null x) (car x))
        (t (cdr x)))
  flop)
;⇒ (1 42)

のようなこともできるようです。

また、(:x y)という式は、(:という記号になり、代入のタグが立ったリストになるそうで、carもcdrも取れるとのこと(どういうことになるのやら)

もう一つ特徴的なのが、自己代入式ですが、

(::cons :x y)

のように書き、CLだと

(seq x (cons x y))

のような動作になります。

この場合でもTAOの場合、xの参照は、代入レジスタのお蔭により1回で済むということです。

また、最後の方は、locativeというMITのLISPマシンでもお馴染のデータ型との組み合わせの解説があります。

locativeだとアドレスを直接扱うことができるのですが、これと件の代入機構と、Smalltalk的なメッセージセンドの構文が融合することによりかなりカオスなことになっていますので、興味のある方にはかなり面白い内容ではないかなと思います。

2010-07-29

KMRCLを眺める(182) DELETE-DIRECTORY-AND-FILES

| 23:28 | KMRCLを眺める(182) DELETE-DIRECTORY-AND-FILES - わだばLisperになる を含むブックマーク はてなブックマーク - KMRCLを眺める(182) DELETE-DIRECTORY-AND-FILES - わだばLisperになる

今回は、KMRCLのos.lispから DELETE-DIRECTORY-AND-FILES です。

Allegro CLだと同名の関数があり、処理系にディレクトリを削除する機能があるようですが、他の処理系の場合はKL:COMMAND-OUTPUTを使って、rm -rfするようです。

定義は、

(defun delete-directory-and-files (dir &key (if-does-not-exist :error) (quiet t) force)
  #+allegro (excl:delete-directory-and-files dir :if-does-not-exist if-does-not-exist
                                             :quiet quiet :force force)
  #-(or allegro) (declare (ignore force))
  #-(or allegro) (cond
                   ((probe-directory dir)
                    (let ((cmd (format nil "rm -rf ~A" (namestring dir))))
                      (unless quiet
                        (format *trace-output* ";; ~A" cmd))
                      (command-output cmd)))
                   ((eq if-does-not-exist :error)
                    (error "Directory ~A does not exist [delete-directory-and-files]." dir))))

となっています。

動作は、

(KL:DELETE-DIRECTORY-AND-FILES "/tmp/bar")
;⇒ ""
    ""
    0
;; 権限不足で削除できなかった場合
;⇒ ""
    "rm: ディレクトリ`/tmp/bar/baz/quux'を削除できません: Permission denied
    "
    1

というところ

2010-07-28

KMRCLを眺める(181) RUN-SHELL-COMMAND

| 13:42 | KMRCLを眺める(181) RUN-SHELL-COMMAND - わだばLisperになる を含むブックマーク はてなブックマーク - KMRCLを眺める(181) RUN-SHELL-COMMAND - わだばLisperになる

今回は、KMRCLのos.lispからRUN-SHELL-COMMANDです。

前回のCOMMAND-OUTPUTは出力を取得できましたが、今回のRUN-SHELL-COMMANDは外部のコマンドを実行するのに特化しています。

動作は、

(LET ((FILE "/usr/share/dict/words")
      (OUT-FILE "/tmp/bar"))
  (WITH-OPEN-FILE (IN FILE)
    (ALEXANDRIA:WITH-OUTPUT-TO-FILE (OUT OUT-FILE)
      (LOOP :FOR LINE := (READ-LINE IN NIL) :WHILE LINE
            :DO (WRITE-LINE (STRING-UPCASE LINE) OUT))))
  (KL:RUN-SHELL-COMMAND "firefox ~A" OUT-FILE))

のようなところでしょうか。

定義は、下記のようになっていますが、処理系依存の切り分けが中身の殆どです。

(defun run-shell-command (control-string &rest args)
  "Interpolate ARGS into CONTROL-STRING as if by FORMAT, and
synchronously execute the result using a Bourne-compatible shell,
returns (VALUES output-string pid)"
  (let ((command (apply #'format nil control-string args)))
    #+sbcl
    (sb-impl::process-exit-code
     (sb-ext:run-program
      "/bin/sh"
      (list  "-c" command)
      :input nil :output nil))

    #+(or cmu scl)
    (ext:process-exit-code
     (ext:run-program
      "/bin/sh"
      (list  "-c" command)
      :input nil :output nil))


    #+allegro
    (excl:run-shell-command command :input nil :output nil
                            :wait t)

    #+lispworks
    (system:call-system-showing-output
     command
     :shell-type "/bin/sh"
     :show-cmd nil
     :prefix ""
     :output-stream nil)

    #+clisp             ;XXX not exactly *verbose-out*, I know
    (ext:run-shell-command  command :output :terminal :wait t)

    #+openmcl
    (nth-value 1
               (ccl:external-process-status
                (ccl:run-program "/bin/sh" (list "-c" command)
                                 :input nil :output nil
                                 :wait t)))

    #-(or openmcl clisp lispworks allegro scl cmu sbcl)
    (error "RUN-SHELL-PROGRAM not implemented for this Lisp")

    ))

2010-07-27

KMRCLを眺める(180) COMMAND-OUTPUT

| 21:42 | KMRCLを眺める(180) COMMAND-OUTPUT - わだばLisperになる を含むブックマーク はてなブックマーク - KMRCLを眺める(180) COMMAND-OUTPUT - わだばLisperになる

今回は、KMRCLのos.lispからCOMMAND-OUTPUTです。

外部のシェルでコマンドを実行したり外部コマンドの出力を取得したりしたくなることは多いと思うのですが、ANSI CLではその辺りのことは決められていませんので、実装依存になります。

しかし、大抵の実装では、外部シェルとやりとりをする一連の関数が提供されています。

COMMAND-OUTPUTはそういうコマンドを処理系に依存しないようにラッピングするものです。

動作は、

(KL:COMMAND-OUTPUT "ls -l /etc/hosts")
;⇒ "-rw-r--r--. 1 root root 1055 2010-07-24 16:51 /etc/hosts
    "
   ""
   0

で、

  1. コマンド出力の文字列
  2. エラー
  3. コマンドの終了コード

と3つの値を返すようになっていて、大体の処理系は、上記3つを取得できる関数を持っているようです。

定義は、処理系ごとに色々違うので長くなっていますが、下記のようになっています。

(defun command-output (control-string &rest args)
  "Interpolate ARGS into CONTROL-STRING as if by FORMAT, and
synchronously execute the result using a Bourne-compatible shell,
returns (VALUES string-output error-output exit-status)"
  (let ((command (apply #'format nil control-string args)))
    #+sbcl
    (let* ((process (sb-ext:run-program
                    "/bin/sh"
                    (list "-c" command)
                    :input nil :output :stream :error :stream))
           (output (read-stream-to-string (sb-impl::process-output process)))
           (error (read-stream-to-string (sb-impl::process-error process))))
      (close (sb-impl::process-output process))
      (close (sb-impl::process-error process))
      (values
       output
       error
       (sb-impl::process-exit-code process)))


    #+(or cmu scl)
    (let* ((process (ext:run-program
                     "/bin/sh"
                     (list "-c" command)
                     :input nil :output :stream :error :stream))
           (output (read-stream-to-string (ext::process-output process)))
           (error (read-stream-to-string (ext::process-error process))))
      (close (ext::process-output process))
      (close (ext::process-error process))

      (values
       output
       error
       (ext::process-exit-code process)))

    #+allegro
    (multiple-value-bind (output error status)
        (excl.osi:command-output command :whole t)
      (values output error status))

    #+lispworks
    ;; BUG: Lispworks combines output and error streams
    (let ((output (make-string-output-stream)))
      (unwind-protect
          (let ((status
                 (system:call-system-showing-output
                  command
                  :prefix ""
                  :show-cmd nil
                  :output-stream output)))
            (values (get-output-stream-string output) nil status))
        (close output)))

    #+clisp
    ;; BUG: CLisp doesn't allow output to user-specified stream
    (values
     nil
     nil
     (ext:run-shell-command  command :output :terminal :wait t))

    #+openmcl
    (let* ((process (ccl:run-program
                     "/bin/sh"
                     (list "-c" command)
                     :input nil :output :stream :error :stream
                     :wait t))
           (output (read-stream-to-string (ccl::external-process-output-stream process)))
           (error (read-stream-to-string (ccl::external-process-error-stream process))))
      (close (ccl::external-process-output-stream process))
      (close (ccl::external-process-error-stream process))
      (values output
              error
              (nth-value 1 (ccl::external-process-status process))))

    #-(or openmcl clisp lispworks allegro scl cmu sbcl)
    (error "COMMAND-OUTPUT not implemented for this Lisp")

    ))

2010-07-26

ABCL/1 ABCL/R2をビルドする

| 23:30 | ABCL/1 ABCL/R2をビルドする - わだばLisperになる を含むブックマーク はてなブックマーク - ABCL/1 ABCL/R2をビルドする - わだばLisperになる

今回のABCLは、JVM上で動くCL処理系ではなくて、LISPベースの並列オブジェクト指向言語の方です。

今日、deliciousから流れてくるLISP関係のものを眺めていて、

というのをみつけました。

中に配布されているソースが書かれているのですが、もしかしてと思って、上のディレクトリを覗いてみると、abcl/1や、abcl/r2のソースがありました!

abcl/fはソースが配布されているのを見たことがあったのですが、abcl/1やabcl/rは配布されていることを知りませんでした。

物は試しということで、早速、ビルドに挑戦。

Makefileもあるのですが、手直ししないと動かないようなので、ターゲットの一つであるKCLの直系のGCLを起動して、処理系からビルド用のファイルを読み込むことにしてみました。

といっても非常に簡単です。(環境は、Ubuntu 10.4 x86_64で試しました。)

abcl/r2の場合

$ mkdir abclr2
$ cd abclr2
$ wget http://venus.is.s.u-tokyo.ac.jp/pub/abclr2/abclr2-dist.tar.Z
$ gzcat abclr2-dist.tar.Z|tar xvf -
$ gcl
GCL (GNU Common Lisp)  2.6.7 CLtL1    Feb 15 2010 17:57:54
Source License: LGPL(gcl,gmp), GPL(unexec,bfd,xgcl)
Binary License:  GPL due to GPL'ed components: (XGCL READLINE BFD UNEXEC)
Modifications of this banner must retain notice of a compatible license
Dedicated to the memory of W. Schelter

Use (help) to get some basic information on how to use GCL.
Temporary directory for compiler files set to /tmp/

>(push :kcl *features*) ;KCLということにする

(:KCL :COMPILER :NUMLIB :SDEBUG :DEFPACKAGE :GNU-LD :XGCL :UNEXEC :BFD
      :NATIVE-RELOC :READLINE :TRUNCATE_USE_C :CLX-LITTLE-ENDIAN :BSD
      :GNU :LINUX :X86_64 :SGC :IEEE-FLOATING-POINT :UNIX :GMP :GCL
      :AKCL :COMMON :KCL)

(load "defabclr2.lsp")

Loading defabclr2.lsp
Loading defsystem.lsp
Finished loading defsystem.lsp
Finished loading defabclr2.lsp
T

>(build-and-dump) ;ビルドして実行可能ファイルを作成

Loading /home/mc/Desktop/abcl/abclr2/src/abclr2.system...
...

とすると、saved_abclr2というものができます。

これを実行すると

$ ./saved_abclr2 

Welcome to ABCL/R2 Gesi version (Jul. 7, 1995, 0.59)

ABCL/R2>[[object (script (=> [:hello] !(print "Hello, World!")))] <== [:hello]]

"Hello, World!" 
"Hello, World!"
ABCL/R2>

abcl/r2が起動できます。

abcl/1のビルド

abcl/1もabcl/r2と同じようにできますが、途中でちょっとひっかかるので、そこは飛します。

>(push :kcl *features*)

(:KCL :COMPILER :NUMLIB :SDEBUG :DEFPACKAGE :GNU-LD :XGCL :UNEXEC :BFD
      :NATIVE-RELOC :READLINE :TRUNCATE_USE_C :CLX-LITTLE-ENDIAN :BSD
      :GNU :LINUX :X86_64 :SGC :IEEE-FLOATING-POINT :UNIX :GMP :GCL
      :AKCL :COMMON :KCL)

>(load "init-abcl")

Loading init-abcl.lsp
ABCL-USER>>  (load "maksys")

Loading maksys.lsp
Finished loading maksys.lsp
t
ABCL-USER>>  (load "defabcl")

Loading defabcl.lsp
Finished loading defabcl.lsp
t
ABCL-USER>>  (maksys 'abcl1)
Loading file   declare.o...... start address -T 0x10bbfe0 done.
ABCL-USER>>  (abcl::enable-debug)
ABCL-USER>>  (abcl::gbc-message-on)
ABCL-USER>>  ; (si:catch-bad-signals);飛ばす
ABCL-USER>>  (setq si:*indent-formatted-output* nil)
ABCL-USER>>  (defun system:top-level nil (abcl::abcl-top-level))
ABCL-USER>>  (if abcl::*distribution* (setq si::*break-enable* nil))
ABCL-USER>>  (gbc t)
ABCL-USER>>  (si:save-system "saved_abcl1")

まだ、マニュアルをちょっと眺めただけですが、abcl面白そうです!

2010-07-25

(41)NUE/TAO/ELISのOS的側面(1984)

| 19:50 | (41)NUE/TAO/ELISのOS的側面(1984) - わだばLisperになる を含むブックマーク はてなブックマーク - (41)NUE/TAO/ELISのOS的側面(1984) - わだばLisperになる

TAO関係の論文を漁っておりますが、今回は、

です。

タイトルは日本語ですが、内容は英文です。

軽くNUEについて説明したあと、マルチプログラミング、OBLISTグラフ(多重の名前空間について)、マルチユーザー対応と説明が続きます。

英文だけに海外のLispマシンとの違いをメインに説明されているように思えました(Zetalispとの比較など)

海外のLispマシンがビットマップディスプレイの個人占有マシンを指向していたのに対し、TAO/ELISのマルチユーザーで、9600bpsのターミナルという立ち位置は面白いなと思いました(高価なビットマップディスプレイは後々に普及してから検討する方針だったようです)

2010-07-24

KMRCLを眺める(179) FILE-SIZE

| 23:14 | KMRCLを眺める(179) FILE-SIZE - わだばLisperになる を含むブックマーク はてなブックマーク - KMRCLを眺める(179) FILE-SIZE - わだばLisperになる

KMRCLを眺める、symbols.lispは前回で終了したので、今回は、KMRCLのos.lispからFILE-SIZEです。

CLでファイルのサイズをみるとなると、OPENして、FILE-LENGTHだと思いますが、FILE-SIZEの定義も

(defun file-size (file)
  (when (probe-file file)
    #+allegro (let ((stat (excl.osi:stat (namestring file))))
                (excl.osi:stat-size stat))
    #-allegro
    (with-open-file (in file :direction :input)
      (file-length in))))

となっています。

Allegro CLだと、excl.osi:stat-size というものがあるようで、ACLの場合はそちらを使うようになっています。

動作は、

(KL:FILE-SIZE "/usr/share/dict/words")
;⇒ 931708

というところ

2010-07-23

KMRCLを眺める(178) GETPID

| 23:48 | KMRCLを眺める(178) GETPID - わだばLisperになる を含むブックマーク はてなブックマーク - KMRCLを眺める(178) GETPID - わだばLisperになる

KMRCLを眺める、symbols.lispは前回で終了したので、今回は、KMRCLのos.lispからGETPIDです。

OS周りはANSI CLの仕様では決められていないので、処理系の伝統だったり処理系が稼動するホストOSの流儀を取り込んだり色々のようです。

GETPIDは、LISP処理系のプロセスIDを取得するというもので、大概の処理系には含まれているもののようです。

動作は、Linux上のSBCLだと

(KL:GETPID)
;⇒ 3018

という感じです。

シェルで確かめてみると

setq% ps | grep 3018
g000001    3018  2570  0 20:18 pts/4    00:00:36 /var/lisp/swank-sbcl

という風に一致していることが分かります。

定義は、

(defun getpid ()
  "Return the PID of the lisp process."
  #+allegro (excl::getpid)
  #+(and lispworks win32) (win32:get-current-process-id)
  #+(and lispworks (not win32)) (system::getpid)
  #+sbcl (sb-posix:getpid)
  #+cmu (unix:unix-getpid)
  #+openmcl (ccl::getpid)
  #+(and clisp unix) (system::process-id)
  #+(and clisp win32) (cond ((find-package :win32)
                             (funcall (find-symbol "GetCurrentProcessId"
                                                   :win32)))
                            (t
                             (system::getenv "PID")))
  )

というところで、処理系依存の切り分けが殆どで、正味は1行です。

2010-07-22

(40)LispマシンELISのアーキテクチャ-メモリレジスタの汎用化とその効果-(1983)

| 22:25 | (40)LispマシンELISのアーキテクチャ-メモリレジスタの汎用化とその効果-(1983) - わだばLisperになる を含むブックマーク はてなブックマーク - (40)LispマシンELISのアーキテクチャ-メモリレジスタの汎用化とその効果-(1983) - わだばLisperになる

TAO関係の論文を漁っておりますが、今回は、

です。

前回眺めた「LispマシンELIS上の新Lisp TAO(1982)」ではTAOが新しくなり3つのパラダイムを扱うようになっていましたが、マシンの側も応じるように変化しています。

マシンの設計においては 命令セット ありきで設計が始まるそうなのですが、ELIS の場合は、LISP処理系でのインタプリタとコンパイルコードの完全両立と、インタプリタの高速化をねらうという所から出発したそうで、

  1. 特定の Lisp に依存しない, リスト処理に共通な機能の充実.
  2. キャッシュメモリなしでもセルアクセスが処理のネックにならないこと.
  3. 集積化の際にも, 実装しやすい構造をもつこと. 集積回路の設計には同一の構造物を繰り返し用いることが望ましい

ということが具体的なアーキテクチャを決定する要因となったそうです。

これらの発想から生まれたのが、「Lisp マシン ELIS の基本設計(1980)」でもちょっと出てきたメモリ多目的レジスタ (MGR) とのこと。

メモリ多目的レジスタの活用例について詳細が述べられています。

ハードウェア関係が分からないので内容は自分には難しいですが、LISPとハードウェアが密に連携していたということはなんとなく分かります。

2010-07-21

KMRCLを眺める(177) RUN-TESTS-FOR-INSTANCE

| 22:39 | KMRCLを眺める(177) RUN-TESTS-FOR-INSTANCE - わだばLisperになる を含むブックマーク はてなブックマーク - KMRCLを眺める(177) RUN-TESTS-FOR-INSTANCE - わだばLisperになる

KMRCLを眺める、今回は、KMRCLのsymbols.lispからFIND-TEST-GENERIC-FUNCTIONSです。

RUN-TESTS-FOR-INSTANCEは、前回の謎関数FIND-TEST-GENERIC-FUNCTIONSを利用するもので定義は、

(defun run-tests-for-instance (instance)
  (dolist (gf-name(find-test-generic-functions instance))
    (funcall gf-name instance))
  (values))

となっています。これから使い方を想像するに

(DEFCLASS FOO () 
  ((X :INITFORM 1 :ACCESSOR FOO-X)
   (Y :INITFORM 2 :ACCESSOR FOO-Y)
   (Z :INITFORM 3 :ACCESSOR FOO-Z)))

(DEFMETHOD TEST-FOO1 ((X FOO))
  (PRINT (LIST '(= 1 (FOO-X (MAKE-INSTANCE 'FOO)))
               '=> 
               (= 1 (FOO-X (MAKE-INSTANCE 'FOO))))))

(DEFMETHOD TEST-FOO2 ((X FOO))
  (PRINT (LIST
          '(= 2 (FOO-Y (MAKE-INSTANCE 'FOO)))
          '=> 
          (= 2 (FOO-Y (MAKE-INSTANCE 'FOO))))))

(DEFMETHOD TEST-FOO3 ((X FOO))
  (PRINT (LIST
          '(= 3 (FOO-Z (MAKE-INSTANCE 'FOO)))
          '=> 
          (= 3 (FOO-Z (MAKE-INSTANCE 'FOO))))))

;; テスト実行
(KL::RUN-TESTS-FOR-INSTANCE (MAKE-INSTANCE 'FOO))
;->
((= 2 (FOO-Y (MAKE-INSTANCE 'FOO))) => T) 
((= 3 (FOO-Z (MAKE-INSTANCE 'FOO))) => T) 
((= 1 (FOO-X (MAKE-INSTANCE 'FOO))) => T)

みたいな感じでしょうか。

とりあえず、TEST-というメソッドを片っ端から実行するんだということは理解できましたが…

2010-07-20

KMRCLを眺める(176) FIND-TEST-GENERIC-FUNCTIONS

| 23:44 | KMRCLを眺める(176) FIND-TEST-GENERIC-FUNCTIONS - わだばLisperになる を含むブックマーク はてなブックマーク - KMRCLを眺める(176) FIND-TEST-GENERIC-FUNCTIONS - わだばLisperになる

KMRCLを眺めるのも久々ですが、今回は、KMRCLのsymbols.lispからFIND-TEST-GENERIC-FUNCTIONSです。

とりあえず、ぱっとみで何をするものなのか良く分からないので、ドキュメントストリングを読んだり、コードを眺めたりですが、動作は、

(DEFCLASS FOO () ())

(DEFMETHOD TEST-FOO ((X FOO)))
(DEFMETHOD TEST-FOO1 ((X FOO)))
(DEFMETHOD TEST-FOO2 ((X FOO)))

(KL::FIND-TEST-GENERIC-FUNCTIONS (MAKE-INSTANCE 'FOO))
;⇒ (TEST-FOO2 TEST-FOO TEST-FOO1)

となるようです。

上では、FOOというクラスを作って、そのFOOに関連する総称関数を作成していて、それらはすべてTEST-という名前で始まっています。

どうも、FIND-TEST-GENERIC-FUNCTIONSは、こういう総称関数を探し出すもののようです。

テストを書くときに使うと便利だったりするんでしょうか…。

定義は、

(defun find-test-generic-functions (instance)
  "Return a list of symbols for generic functions specialized on the
class of an instance and whose name begins with the string 'test-'"
  (let ((res)
        (package (symbol-package (class-name (class-of instance)))))
    (do-symbols (s package)
      (multiple-value-bind (sym status)
          (find-symbol (symbol-name s) package)
        (when (and (or (eq status :external)
                       (eq status :internal))
                   (fboundp sym)
                   (eq (symbol-package sym) package)
                   (> (length (symbol-name sym)) 5)
                   (string-equal "test-" (subseq (symbol-name sym) 0 5))
                   (typep (symbol-function sym) 'generic-function)
                   (plusp
                    (length
                     (compute-applicable-methods
                      (ensure-generic-function sym)
                      (list instance)))))
          (push sym res))))
    (nreverse res)))

となっています。

2010-07-19

(39)LispマシンELIS上の新Lisp TAO(1982)

| 04:18 | (39)LispマシンELIS上の新Lisp TAO(1982) - わだばLisperになる を含むブックマーク はてなブックマーク - (39)LispマシンELIS上の新Lisp TAO(1982) - わだばLisperになる

TAO関係の論文を漁っておりますが、今回は、

です。

これまで眺めた論文では、LISP+Prologという感じでしたが、本文あたりからSmalltalkが加わるようです。

内容は、Prologとの融合、Smalltalkとの融合という流れて進みます。

Prologとの融合

まずは、Prologとの融合で、ユニフィケーションの関数化について説明があり、無名関数のLAMBDAのようにユニフィケーションが書けるようです。

((lambda (x) (car x)) '(1 2 3 4))

に対して

((&+ (*x . *y) *x) (1 2 3 4))
; ⇒ 1

これは主にパターンマッチの機能で比較的分かりやすいかと思います。

次にバックトラックなどですが、

(Hclauses (&+ ...) ... (&+ ...))

という形式で、本体内の式でnon-NILな式があればその値を返し、そうでなければバックトラックする述語の無名関数版のようなHclausesが基本になるようです

((Hclauses (&+ (*x *y . *z) *x) (&+ (*x *y *x) *y)) (1 (*a 2) *a))

は、Prologでいう

hclauses([X,Y|Z], X).
hclauses([X,Y,X], Y).

?- hclauses([1,[A,2],A],X).
X = 1 ; (バックトラックさせる)
A = 1,
X = [1, 2].

のようなものの無名版のようです。

他には&や、!があり、prologのように、","で継げて書くには、&を利用するようです。

(& (*x *y)    
   (belong *x (1 2))  
   (print (list 'pre *x (if-undef *y 'U)))
   (belong *y (4 2))                      
   (print (list 'post *x *y))             
   (== *x *y) )

は、

?- belong(X,[1,2]),
    print([pre, X]),nl,
    belong(Y,[4,2]),
    print([post,Y]),nl,
    X=Y.
[pre, 1]
[post, 4]
[post, 2]
[pre, 2]
[post, 4]
[post, 2]
X = 2,
Y = 2 ;
false.
% belongの定義
belong(X,[X|_]).
belong(X,[A|Y]) :- belong(X,Y).

的な感じなのでしょうか。

また、Prologと違う点は、論理変数にはスコープを設定でき(上のコードの例でいうと&の次のリストで利用する変数を宣言している)、このスコープによって色々と挙動を変化させることができるとのことで、挙動の違いの解説があります。

Smalltalkとの融合

ぱっと見た感じでは、MITのFlavorsのような感じですが、角括弧の記法で、

[<receiver> <message> . <args> ]

と書けるようです。

[3 + 4]
;⇒ 7

と表現できるようなのですが、丸括弧も使えるようなので

(3 + 4)
;⇒ 7

(defun factorial (n)
  (cond (n = 0) 1)
        (t (n * (factorial (n - 1)))) )

のように部分的に中置だったり前置だったりカオスな記述もできたようです。

パフォーマンスについては、「TAO では Lisp で定義した append と Prolog 風に定義した append の速度比は 1:1.5 以内, Lisp 式 (+ x y) と Smalltalk 風の (x + y) とは同速度となっている.」とのことで3つのパラダイムは十分に混合して利用できたようです。

2010-07-18

(38)New Unified Environment(NUE)の基本構想(1982)

| 01:03 | (38)New Unified Environment(NUE)の基本構想(1982) - わだばLisperになる を含むブックマーク はてなブックマーク - (38)New Unified Environment(NUE)の基本構想(1982) - わだばLisperになる

TAO関係の論文を漁っておりますが、今回は、

です。

これまで眺めてきたELISのプロトタイプはTAO/60で記述されていて、TAO/60は既存のLISPの拡張という感じなのですが、1982年のNUE(New Unified Environment)辺りからLisp+Prolog+Smalltalkという感じになってきます。

本文では、まだSmalltalkの取り込みの話はでてきておらず、Prologとの融合について解説されています。

まず、複数のパラダイムを統合する核言語としてLISPを採用した理由が述べられていますが「むしろ Lisp というより, S式という「前言語的言語」を基本枠組として選んだと言えよう」とのことで、S式の柔軟性が理由のようです。

また、S式については、「S式についてもう1つ注意しておかなければならないのは, 人間と機械の間の「共通言語 (深層言語)」としてのS式の優位性, 自然さである. S式は入出力が常に整形されていれば人間にとって決して扱いにくいものではない. もちろん機械にとってS式は機械内部表現と1対1に対応している. 我々はS式が, 人間と機械の双方向通信にとって, 少なくとも現時点の我々の技術レベルにおいて, 最も自然で直接的であると考える. 」とも述べられていてS式LOVEな人にとっては頷けるところも多いかと思います。

また後半は、PrologとLISPの融合について述べられていますが、当時の同様の試みであるLOGLISP、PROLOG/KR、DURAL等との比較が述べられています。

ちょっとした発見としては、論理変数は、TAO/ELISでは、

(equall _x _u)

のように_を付けて書きますが、この本文の時点では、Prolog/KRのように

(equall *x *u)

と書いていたようで、色々と模索が伺えます

2010-07-16

(37)A Principle of New Programming Environment(1981)

| 21:16 | (37)A Principle of New Programming Environment(1981) - わだばLisperになる を含むブックマーク はてなブックマーク - (37)A Principle of New Programming Environment(1981) - わだばLisperになる

TAO関係の論文を漁っておりますが、今回は、

です。

本文は、NUE (New Unified Environment)という、(1) Lisp machine (ELIS) 上で, (2) 主として玄人の programmer が, (3) display 端末を介して, 高度に対話的に, (5) かなり大規模な programming を行なうためのプログラミング環境の構想について述べられています。

LISPの処理系側の大規模なプログラミングをするための工夫としては、OblistをノードとしたOblist graphというものを考え、これにより同一のシンボル名を扱うことを可能にしているとのこと。

また、対話環境については、Emacsのようなモードレスなエディタを想定していて、コマンドの履歴や処理のバックグラウンド化や切り替えにも対応するということで、当時のMITやXeroxのLispマシン相当の機能は想定されていたようです。(当時のMITのLispマシンの開発環境は今でいうSLIMEのような機能を既に実現していました)

また、他のLispマシンがAltoのようなシングルユーザー向けの環境であるのに対してTAOはTSS的にマルチユーザーであることを指向していたようなのですが、ここでも「2人以上の人間が同一の Lisp 環境で共同作業を行なえる. また1人の人間が複数の window を通じて, 同一のみならず別の Lisp 環境と対話できる.」ことを掲げています。

それにしても、マルチユーザーのLISP環境というのは面白そうですね。

2010-07-15

(36)LispマシンELISの開発環境(1982)

| 23:03 | (36)LispマシンELISの開発環境(1982) - わだばLisperになる を含むブックマーク はてなブックマーク - (36)LispマシンELISの開発環境(1982) - わだばLisperになる

TAO関係の論文を漁っておりますが、今回は、

です。

開発環境といっても本文は高レベルではなくハードに近い低レベルの方の開発環境です。

ELISの開発環境としてのAO/60用いたマイクロプログラミング支援のためのアセンブラ、リンカ、ローダーについて詳細に述べられています。

紹介されているマイクロアセンブラもまたリストで表現されていて、所謂LAP(List Assembly Program)というものだと思うのですが、なんでもLISTで表現できる/するんだなあと感心します。

延々と実装戦略等が述べられていて自分にはハードな内容でした。

LISPマシンを作ってみたいという方には色々面白いところがあるのではないでしょうか。

2010-07-13

(35)LISPマシンELISの基本設計(1980)

| 22:40 | (35)LISPマシンELISの基本設計(1980) - わだばLisperになる を含むブックマーク はてなブックマーク - (35)LISPマシンELISの基本設計(1980) - わだばLisperになる

TAO関係の論文を漁っておりますが、今回は、

です。

本文はLISPマシンELISの設計方針と実現について書かれています。

当時、AI研究の道具としてつかえる大型LISPマシンが望まれる時代になっていたようで、ELISも実行速度、記憶容量、システムの使い勝手、それぞれの向上を目標にしていたようです。

本文ではそれぞれについて詳細な解説がありますが、使い勝手の要素の一つと思われるコンパイラとインタプリタの動作についても述べられています。

TAO LISPではインタプリタとコンパイラの両立(コンパイルされた関数もそうでない関数もいりまじって一緒に使うことができ実行結果も同一であること)を常にねらっていたそうで、この方針を進めるためインタプリタの全面的なマイクロコード化(今でいうファームウェア的な層での実装)がされたそうです。

Common Lispもコンパイルされた関数とインタプリタでの挙動の一貫性を目標の一つに挙げていますが、CLはコンパイラ指向に傾いたのとは対照的だなと思いました。

他、かなりハードウェア寄りな内容ですが、言語とハードウェアが相互に影響しあうシステムは素敵だなと思います。

2010-07-12

(34)TAO LISPについて(1979)

| 08:14 | (34)TAO LISPについて(1979) - わだばLisperになる を含むブックマーク はてなブックマーク - (34)TAO LISPについて(1979) - わだばLisperになる

いつもはまったりとCiNiiのLISP関係の論文を漁っておりますが、情報学広場:情報処理学会電子図書館 というところでも論文のPDFが読めるようになっているのをみつけました。

以前からTAO関係で読んでみたいなと思っていたものがあるので、早速眺めてみます。

本文のTAOは、PDP-11/60上での実装のため、TAO/60と呼ばれるらしいです。

色々特徴がありますが、まず、関数は、当時のLISP処理系の慣習だとLAMBDAで初まるLISTとして表現されていましたが、TAO/60では、指定されたVTITLE(ベクターの標識/SYMBOLでいうプロパティのようなもの?)を持つベクターが関数になるとのことです。

ここから、配列は、添字を引数とする関数、大域変数は引数の無い関数、という解釈が導かれるとのこと。

ベクターが添字を引数とする関数になるというのは、Clojureのような動きですね。

また、関数の定義で、CLでいう&OPTIONAL、&RESTなどに加え、引数を評価しない書法がある様子。

(DE F (X (Y 0))
  (LIST X Y))

(F 8) ;=> (8 0)

(DE F (X REST Y)
  (LIST X Y))

(F 8 9 0 1) ;=> (8 (9 0 1))

(DE F (X 'Y)
  (LIST X Y))

(F 8 A) ;=> (8 A)

また、複値形式(Double Valued Form)というのがあり、

;; 
(:X (+ X 1))

;; Aは(1 2 3 4 5 6)のようなベクター

(:(A 3) 0)

A ;=> (1 2 3 0 5 6)

という風にCLでいうSETFのように振る舞うようです。TAO/ELISでは、!で書いているのと同じものでしょうか。

この形式は、値と、どこに書き戻したら良いのかという二つの情報を持つので複値形式と呼ぶようです。

TAO/60では、この複値形式を駆使している様子。

その他、変数のスコープ等、色々興味深い内容です。

2010-07-10

(33)TAO/ELISのUNIXへの移植(1995)

| 23:32 | (33)TAO/ELISのUNIXへの移植(1995) - わだばLisperになる を含むブックマーク はてなブックマーク - (33)TAO/ELISのUNIXへの移植(1995) - わだばLisperになる

まったりとCiNiiのLISP関係の論文を漁っております。

来月8月7〜9はJAISTでELIS復活祭ということで私も3日間参加することにしました。

もちろん月曜は会社を休みますw

東京からだとJAISTって結構遠いみたいですが、一緒に電車でJAISTに行って頂ける方を募集しています。

ということで、折角のELIS復活祭に向けてCiNiiの論文漁りもTAO/ELIS関係を中心に眺めていこうかなと思います。

ということで、今回は、

です。

本文は、ELISというLISPマシンのマイクロコードをまるごとCに変換してFreeBSD上でTAO/ELISを稼動させたという内容です。

1995年のPentium II 300MHzのマシンで実機の2.5倍のスピードで稼動したとのこと。

また、TAO/ELISはLISPマシンにしては他に類をみないマルチユーザー環境ですが、移植環境でも8人までログインして同時につかえるとのこと。

また、本文の6年後に続編ような「マイクロプログラムの静的変換による記号処理システムの移植とその性能評価」が書かれているのですが、nue.orgでもHTML版が読めるので、改めてHTMLを眺めてみたところ、なんと内容がアップデートされていました!

FreeBSD 8.0や、MacOSXに移植しオリジナルの70倍のスピードで動くとのこと。

TAOプログラムもすべて動くようになっているとのことです。凄いですね!

KMRCLを眺める(175) SHOW

| 00:13 | KMRCLを眺める(175) SHOW - わだばLisperになる を含むブックマーク はてなブックマーク - KMRCLを眺める(175) SHOW - わだばLisperになる

今回は、KMRCLのsymbols.lispからSHOWです。

前回、前々回のSHOW-VARIABLES、SHOW-FUNCTIONSを纒めたものです。

動作は、

(KL:SHOW :FUNCTIONS :G000001)
;->
Function GITHUB-INSTALL  -> #<FUNCTION GITHUB-INSTALL>
Function AUTO-IMPORT  -> #<FUNCTION AUTO-IMPORT>
Function QUIT  -> #<FUNCTION QUIT>
Function FACT-CPS-LIST  -> #<FUNCTION FACT-CPS-LIST>
Function INSTALL  -> #<FUNCTION INSTALL>
Function OOS  -> #<FUNCTION OOS>
Function CURRY  -> #<FUNCTION CURRY>
Function FACT-CPS  -> #<FUNCTION FACT-CPS>
Function FLATTEN-CPS  -> #<FUNCTION FLATTEN-CPS>
;⇒ NIL

というところ。定義は、

(defun show (&optional (what :variables) (package *package*))
  (ecase what
    (:variables (show-variables package))
    (:functions (show-functions package))))

となっています。

ざっと一覧を眺めるのに便利かもしれません。

2010-07-08

KMRCLを眺める(174) SHOW-FUNCTIONS

| 22:41 | KMRCLを眺める(174) SHOW-FUNCTIONS - わだばLisperになる を含むブックマーク はてなブックマーク - KMRCLを眺める(174) SHOW-FUNCTIONS - わだばLisperになる

今回は、KMRCLのsymbols.lispからSHOW-FUNCTIONSです。

前回は、変数でしたが今回はそれの関数版です。

動作は、

(KL:SHOW-FUNCTIONS :KMRCL)
->
Function KMRCL::STRING-DEFAULT-CASE  -> #<FUNCTION KMRCL::STRING-DEFAULT-CASE>
Function KMRCL::BYTE-ARRAY-OUTPUT-STREAM-OUT  -> #<CLOSURE (LAMBDA
                                                               (SB-KERNEL:INSTANCE)) {1004F93809}>
Function KMRCL::%PRINT-BYTE-ARRAY-OUTPUT-STREAM  -> #<FUNCTION KMRCL::%PRINT-BYTE-ARRAY-OUTPUT-STREAM>
Function KMRCL::BYTE-ARRAY-INPUT-STREAM-CHAR-SIZE  -> #<CLOSURE (LAMBDA
                                                                    (SB-KERNEL:INSTANCE)) {1004E9ADD9}>
Function KMRCL::BYTE-ARRAY-OUTPUT-STREAM-EOF-FORCED-P  -> #<CLOSURE (LAMBDA
                                                                        (SB-KERNEL:INSTANCE)) {10041AA599}>
Function KMRCL::BYTE-ARRAY-OUTPUT-STREAM-EXTERNAL-FORMAT  -> #<CLOSURE (LAMBDA
                                                                           (SB-KERNEL:INSTANCE)) {100535A469}>
Function KMRCL::BYTE-ARRAY-INPUT-STREAM-DUAL-CHANNEL-P  -> #<CLOSURE (LAMBDA
                                                                         (SB-KERNEL:INSTANCE)) {10044000B9}>
Function KMRCL::CL-SYMBOLS  -> #<FUNCTION KMRCL::CL-SYMBOLS>
Function KMRCL::BYTE-ARRAY-OUTPUT-STREAM-PATHNAME  -> #<CLOSURE (LAMBDA
                                                                    (SB-KERNEL:INSTANCE)) {1005353729}>
Function KMRCL::BYTE-ARRAY-OUTPUT-STREAM-DELETE-ORIGINAL  -> #<CLOSURE (LAMBDA
                                                                           (SB-KERNEL:INSTANCE)) {10059CD009}>
Function KMRCL::BYTE-ARRAY-INPUT-STREAM-LISTEN  -> #<CLOSURE (LAMBDA
                                                                 (SB-KERNEL:INSTANCE)) {1005A87D89}>
Function KMRCL::REMOTE-HOST  -> #<FUNCTION KMRCL::REMOTE-HOST>
Function KMRCL::REPL-ON-STREAM  -> #<FUNCTION KMRCL::REPL-ON-STREAM>
Function KMRCL::BYTE-ARRAY-BINCH  -> #<FUNCTION KMRCL::BYTE-ARRAY-BINCH>
Function KMRCL::CATCH-ERRORS  -> #<STANDARD-GENERIC-FUNCTION KMRCL::CATCH-ERRORS (1)>
Function KMRCL::BYTE-ARRAY-OUTPUT-STREAM-INSTEAD  -> #<CLOSURE (LAMBDA
                                                                   (SB-KERNEL:INSTANCE)) {1005586FB9}>
Function KMRCL::BUF-USED  -> #<CLOSURE (LAMBDA (SB-KERNEL:INSTANCE)) {10040F4CB9}>
Function KMRCL::BYTE-ARRAY-INPUT-STREAM-TIMEOUT  -> #<CLOSURE (LAMBDA
                                                                  (SB-KERNEL:INSTANCE)) {10053D5B79}>
Function KMRCL::BUF-POP  -> #<FUNCTION KMRCL::BUF-POP>
Function KMRCL::BYTE-ARRAY-INPUT-STREAM-BIN  -> #<CLOSURE (LAMBDA
                                                              (SB-KERNEL:INSTANCE)) {1004E19F49}>
Function KMRCL::BYTE-ARRAY-IN-MISC  -> #<FUNCTION KMRCL::BYTE-ARRAY-IN-MISC>
Function KMRCL::BYTE-ARRAY-INPUT-STREAM-BUFFERING  -> #<CLOSURE (LAMBDA
                                                                    (SB-KERNEL:INSTANCE)) {100517C1B9}>
Function KMRCL::MAPCAR2-APPEND-STRING-NONTAILREC  -> #<FUNCTION KMRCL::MAPCAR2-APPEND-STRING-NONTAILREC>
Function KMRCL::BUF-P  -> #<CLOSURE (LAMBDA (SB-KERNEL::OBJECT)) {100463FB59}>
Function KMRCL::BYTE-ARRAY-INPUT-STREAM-NAME  -> #<CLOSURE (LAMBDA
                                                               (SB-KERNEL:INSTANCE)) {1004245D19}>
Function KMRCL::CANONICALIZE-DIRECTORY-NAME  -> #<FUNCTION KMRCL::CANONICALIZE-DIRECTORY-NAME>
Function KMRCL::FIELD-BUFFERS-BUFFERS  -> #<CLOSURE (LAMBDA
                                                        (SB-KERNEL:INSTANCE)) {100529FFB9}>
Function KMRCL::BYTE-ARRAY-INPUT-STREAM-BYTE-ARRAY  -> #<CLOSURE (LAMBDA
                                                                     (SB-KERNEL:INSTANCE)) {1005979BF9}>
Function KMRCL::BASE-NAME  -> #<STANDARD-GENERIC-FUNCTION KMRCL::BASE-NAME (1)>
Function KMRCL::BYTE-ARRAY-INPUT-STREAM-BOUT  -> #<CLOSURE (LAMBDA
                                                               (SB-KERNEL:INSTANCE)) {1004738469}>
Function KMRCL::BYTE-ARRAY-OUTPUT-STREAM-BUFFERING  -> #<CLOSURE (LAMBDA
                                                                     (SB-KERNEL:INSTANCE)) {100461D8B9}>
Function KMRCL::MAKE-FD-STREAM  -> #<FUNCTION KMRCL::MAKE-FD-STREAM>
....

となっています。定義は、

(defun show-functions (package)
  (do-symbols (s package)
    (multiple-value-bind (sym status)
        (find-symbol (symbol-name s) package)
      (when (and (or (eq status :external)
                     (eq status :internal))
                 (fboundp sym))
        (format t "~&Function ~S~T -> ~S~%"
                sym
                (symbol-function sym))))))

で、変数版とほぼ同一です。

2010-07-07

KMRCLを眺める(173) SHOW-VARIABLES

| 22:25 | KMRCLを眺める(173) SHOW-VARIABLES - わだばLisperになる を含むブックマーク はてなブックマーク - KMRCLを眺める(173) SHOW-VARIABLES - わだばLisperになる

今回は、KMRCLのsymbols.lispからSHOW-VARIABLESです。

変数が束縛されたシンボルとその内容を表示するもののようです。

動作は、

(KL:SHOW-VARIABLES :CL)
->
Symbol *ERROR-OUTPUT*  -> #<SWANK-BACKEND::SLIME-OUTPUT-STREAM
                            {100E6B7271}>
Symbol CALL-ARGUMENTS-LIMIT  -> 1152921504606846975
Symbol *PRINT-BASE*  -> 10
Symbol MOST-NEGATIVE-SINGLE-FLOAT  -> -3.4028235e38
Symbol *LOAD-PRINT*  -> NIL
Symbol *GENSYM-COUNTER*  -> 2959
Symbol BOOLE-ANDC1  -> 12
Symbol BOOLE-C2  -> 5
Symbol LEAST-NEGATIVE-SINGLE-FLOAT  -> -1.4012985e-45
Symbol ARRAY-TOTAL-SIZE-LIMIT  -> 1152921504606846973
Symbol LONG-FLOAT-EPSILON  -> 1.1102230246251568d-16
Symbol *PRINT-RADIX*  -> NIL
Symbol *PRINT-CASE*  -> :UPCASE
Symbol LEAST-POSITIVE-NORMALIZED-SHORT-FLOAT  -> 1.1754944e-38
Symbol ARRAY-RANK-LIMIT  -> 65529
Symbol +  -> (COMMON-LISP-USER::LOGIN 'COMMON-LISP-USER::MC)
Symbol LEAST-POSITIVE-DOUBLE-FLOAT  -> 4.9406564584124654d-324
Symbol ***  -> NIL
Symbol MOST-NEGATIVE-LONG-FLOAT  -> -1.7976931348623157d308
Symbol DOUBLE-FLOAT-EPSILON  -> 1.1102230246251568d-16
Symbol *  -> T
Symbol *LOAD-VERBOSE*  -> NIL
Symbol CHAR-CODE-LIMIT  -> 1114112
Symbol LEAST-NEGATIVE-LONG-FLOAT  -> -4.9406564584124654d-324
Symbol MOST-POSITIVE-LONG-FLOAT  -> 1.7976931348623157d308
Symbol BOOLE-AND  -> 6
Symbol BOOLE-ORC2  -> 15
Symbol MOST-NEGATIVE-FIXNUM  -> -1152921504606846976
Symbol *PRINT-CIRCLE*  -> NIL
....

となっています。定義は、

(defun show-variables (package)
  (do-symbols (s package)
    (multiple-value-bind (sym status)
        (find-symbol (symbol-name s) package)
      (when (and (or (eq status :external)
                     (eq status :internal))
                 (boundp sym))
        (format t "~&Symbol ~S~T -> ~S~%"
                sym
                (symbol-value sym))))))

で、そのままな感じです。

2010-07-06

KMRCLを眺める(172) ENSURE-KEYWORD-DEFAULT-CASE

| 22:12 | KMRCLを眺める(172) ENSURE-KEYWORD-DEFAULT-CASE - わだばLisperになる を含むブックマーク はてなブックマーク - KMRCLを眺める(172) ENSURE-KEYWORD-DEFAULT-CASE - わだばLisperになる

今回は、KMRCLのsymbols.lispからENSURE-KEYWORD-DEFAULT-CASEです。

大文字小文字の違いをKMRCL内で調べてある稼働中の処理系のREADTABLE-CASEの状況に合せてキーワードシンボルを作成します。

動作は、

(LET ((*READTABLE* (COPY-READTABLE)))
  (EVAL
   (READ-FROM-STRING "(kl:ensure-keyword-default-case 'foo)")))
;⇒ :FOO

(LET ((*READTABLE* (COPY-READTABLE)))
  (SETF (READTABLE-CASE *READTABLE*) :PRESERVE)
  (EVAL
   (READ-FROM-STRING "(KL:ENSURE-KEYWORD-DEFAULT-CASE 'foo)")))
;⇒ :FOO

というところ。

:PRESERVEにしていますが、上のテストの*READTABLE*は標準の状態なので全部大文字にされています。

定義は、

(defun ensure-keyword-default-case (desig)
  (nth-value 0 (intern (string-default-case
                        (symbol-name (ensure-keyword desig))) :keyword)))

となっています。

2010-07-05

common-lisp-users.jp 稼動させました

| 01:03 | common-lisp-users.jp 稼動させました - わだばLisperになる を含むブックマーク はてなブックマーク - common-lisp-users.jp 稼動させました - わだばLisperになる

2008年の*-users.jpブームから2年程経過しましたが、いまさらのcommon-lisp-users.jpを作成してみました。

wikiなのでどなたでも書き込めます。

いろいろなCommon Lispまとめサイトと被るところが多い気がするんですが、FAQとか充実させてみたいですねー。

ちなみに、WikiならCommon LispのCLikiを使いたい!と思ったのですが、Wilikiです。

2010-07-04

(32)Concurrent Common LISP(1988)

| 20:20 | (32)Concurrent Common LISP(1988) - わだばLisperになる を含むブックマーク はてなブックマーク - (32)Concurrent Common LISP(1988) - わだばLisperになる

まったりとCiNiiのLISP関係の論文を漁っておりますが、今回は、

Concurrent Common LISPは、Concurrent LISPというLISP1.5をベースに並列処理機能を付加した処理系のベースをCommon Lispにしたもののようです。

Concurrent LISPでは、プロセスは、それ単体でフォームを評価することができる実体として定義されているそうで特徴としては、

  1. 動的に起動され親子関係がある
  2. プロセスのIDもしくは、プロセスの親子関係でプロセスを特定できる
  3. プロセス間のコミュニケーションのため変数の共有とメッセージの送信機能がある

等があるそうです。

Common Lispには並列の機能はありませんが、並列機能の拡張として

  • starteval
  • cr
  • ccr

という3つのスペシャルフォームを用意しているようです。

また、プロセス間の変数の共有は、親プロセスの大域変数で行なうとのこと。

ちなみに、Concurrent Common LISPが稼動していたマシンはどうやらSonyのNEWSだった模様。

2010-07-03

KMRCLを眺める(171) ENSURE-KEYWORD-UPCASE

| 22:07 | KMRCLを眺める(171) ENSURE-KEYWORD-UPCASE - わだばLisperになる を含むブックマーク はてなブックマーク - KMRCLを眺める(171) ENSURE-KEYWORD-UPCASE - わだばLisperになる

今回は、KMRCLのsymbols.lispからENSURE-KEYWORD-UPCASEです。

前回のENSURE-KEYWORDと同じく文字列指示子的なものを与えると、キーワードシンボルを返すというものですが、結果が大文字になることを保証するもののようです。

動作は、

(LET ((*READTABLE* (COPY-READTABLE)))
  (SETF (READTABLE-CASE *READTABLE*) :DOWNCASE)
  (EVAL
   (READ-FROM-STRING "(|KL|:|ENSURE-KEYWORD-UPCASE| 'foo)")))
;⇒ :FOO

というところで、ENSURE-KEYWORDと同じ条件(標準のREADTABLEでない状態)で比較すると

(LET ((*READTABLE* (COPY-READTABLE)))
  (SETF (READTABLE-CASE *READTABLE*) :DOWNCASE)
  (EVAL
   (READ-FROM-STRING "(|KL|:|ENSURE-KEYWORD| 'foo)")))
;⇒ :|foo|

動作が違ってきているのが分かります。

定義は、

(defun ensure-keyword-upcase (desig)
  (nth-value 0 (intern (string-upcase
                        (symbol-name (ensure-keyword desig))) :keyword)))

となっていますが、ENSURE-KEYWORDの使われ方が微妙な気が…

desigは文字列指示子を期待していて、STRING-UPCASEも同様なので、これなら

(defun ensure-keyword-upcase (desig)
  (nth-value 0 (ensure-keyword (string-upcase desig))))

でもOKな気がします。

いやENSURE-KEYWORDが*READTABLE*の値に影響を受けるので、

(defun ensure-keyword-upcase (desig)
  (nth-value 0 (intern (string-upcase desig) :keyword)))

等でないと駄目か。

2010-07-02

(31)第二回 Lisp コンテスト(1979)

| 23:20 | (31)第二回 Lisp コンテスト(1979) - わだばLisperになる を含むブックマーク はてなブックマーク - (31)第二回 Lisp コンテスト(1979) - わだばLisperになる

まったりとCiNiiのLISP関係の論文を漁っておりますが、今回は、

です。

日本でLispが流行しはじめた(情報処理学会で注目され始めた)のは、1974年7月の記号処理シンポジウムがきっかけだったとのことで、この時に初めて日本中のLispに興味のある人々が一堂に会したそうです。

第一回 Lisp コンテストが開催され、日本のLispの状況があきらかになったとのこと。

第二回 Lisp コンテストは、第一回の内容を継承しつつ海外からの参加も呼び掛けてみていたようです。

コンテストの内容ですが、基本的には、ベンチマークで処理系の速度を測るというもので、本文に詳しくベンチの解説があります。

また、当時の処理系はかなり多様で参加者はそれぞれ別の方言という感じですが、共通で動かせるようなものがお題になっています。

ちょっと調べたところでは、第三回まで開催されていた様子で、三回目は、1985年に、第一回 Prologコンテストと共に実施されたようです。

そのうち第四回が開催されることを期待したいですね。

2010-07-01

KMRCLを眺める(170) ENSURE-KEYWORD

| 20:47 | KMRCLを眺める(170) ENSURE-KEYWORD - わだばLisperになる を含むブックマーク はてなブックマーク - KMRCLを眺める(170) ENSURE-KEYWORD - わだばLisperになる

今回は、KMRCLのsymbols.lispからENSURE-KEYWORDです。

文字列指示子的なものを与えると、キーワードシンボルを返すというものです。

動作は、

(KL:ENSURE-KEYWORD "foo")
;⇒ :FOO

(KL:ENSURE-KEYWORD 'foo)
;⇒ :FOO

(KL:ENSURE-KEYWORD :foo)
;⇒ :FOO

というところ。

定義は、

(defun ensure-keyword (name)
  "Returns keyword for a name"
  (etypecase name
    (keyword name)
    (string (nth-value 0 (intern (string-default-case name) :keyword)))
    (symbol (nth-value 0 (intern (symbol-name name) :keyword)))))

となっています。

多値の1値目を返すには、(VALUES)を使うのが定番かと思いますが、丁寧にNTH-VALUEで書いているようです。