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-06-30

引数の順番を覚えられないならELTを使えば良いじゃない!

| 23:40 | 引数の順番を覚えられないならELTを使えば良いじゃない! - わだばLisperになる を含むブックマーク はてなブックマーク - 引数の順番を覚えられないならELTを使えば良いじゃない! - わだばLisperになる

Common Lispには、シーケンスのN番目の要素を取り出すのに、リスト専用ならNTH、ベクタならSVREFとかAREF、文字列ならCHAR、そして汎用には、ELTがありますが、NTHだけ順番が違っていたりする所為で、「おや、どっちの引数がインデックスだったかな」などと記憶が朧げになることがあります。(引数の順番が色々違うのは恐らく歴史的経緯+互換性のため)

そこで、とりあえず、ELTで書いて処理系の最適化に期待してみるのはどうかなと思い試してみました。

試した処理系はSBCLです。

まず、最初に最適化してないELTを呼ぶ関数ELEMENT

(DEFUN ELEMENT (OBJ INDEX)
  (ELT OBJ INDEX))

; disassembly for ELEMENT
; 0E4BA8EB:       488BD6           MOV RDX, RSI               ; no-arg-parsing entry point
;      8EE:       498BF8           MOV RDI, R8
;      8F1:       488B0598FFFFFF   MOV RAX, [RIP-104]         ; #<FDEFINITION object for ELT>
;      8F8:       B910000000       MOV ECX, 16
;      8FD:       FF7508           PUSH QWORD PTR [RBP+8]
;      900:       FF6009           JMP QWORD PTR [RAX+9]
;      903:       CC0A             BREAK 10                   ; error trap
;      905:       02               BYTE #X02
;      906:       18               BYTE #X18                  ; INVALID-ARG-COUNT-ERROR
;      907:       54               BYTE #X54                  ; RCX

ディスアセンブルすると、ELTを呼んでいるだけのようです。

NTHを使うとどうか

(DEFUN ELEMENT/LIST (OBJ INDEX)
  (NTH INDEX OBJ))

; disassembly for ELEMENT/LIST
; 0E6188ED:       488D5C24F0       LEA RBX, [RSP-16]          ; no-arg-parsing entry point
;      8F2:       4883EC18         SUB RSP, 24
;      8F6:       488B55F0         MOV RDX, [RBP-16]
;      8FA:       488B7DF8         MOV RDI, [RBP-8]
;      8FE:       488B058BFFFFFF   MOV RAX, [RIP-117]         ; #<FDEFINITION object for NTHCDR>
;      905:       B910000000       MOV ECX, 16
;      90A:       48892B           MOV [RBX], RBP
;      90D:       488BEB           MOV RBP, RBX
;      910:       FF5009           CALL QWORD PTR [RAX+9]
;      913:       8BC2             MOV EAX, EDX
;      915:       240F             AND AL, 15
;      917:       3C07             CMP AL, 7
;      919:       750F             JNE L0
;      91B:       488B52F9         MOV RDX, [RDX-7]
;      91F:       488BE5           MOV RSP, RBP
;      922:       F8               CLC
;      923:       5D               POP RBP
;      924:       C3               RET
;      925:       CC0A             BREAK 10                   ; error trap
;      927:       02               BYTE #X02
;      928:       18               BYTE #X18                  ; INVALID-ARG-COUNT-ERROR
;      929:       54               BYTE #X54                  ; RCX
;      92A: L0:   CC0A             BREAK 10                   ; error trap
;      92C:       02               BYTE #X02
;      92D:       02               BYTE #X02                  ; OBJECT-NOT-LIST-ERROR
;      92E:       95               BYTE #X95                  ; RDX

NTHCDRを呼ぶようです。

ここで、ELTの定義にジャンプ(M-.)して定義を眺めてみると、リストの場合、

(deftransform elt ((s i) (list *) * :policy (< safety 3))
  '(nth i s))

という風に最適化のための変形が定義されていて、(OPTIMIZE (SAFETY N))のNを3より低く0〜2にすれば変形が発動するようです。

ということで、オブジェクトがリストであることを指定しつつ、SAFETYを0にしてみてディスアセンブル

(DEFUN ELEMENT/LIST-OPT (OBJ INDEX)
  (DECLARE (OPTIMIZE (SAFETY 0))
           (LIST OBJ))
  (ELT OBJ INDEX))

; disassembly for ELEMENT/LIST-OPT
; 0E5468E7:       488B55F0         MOV RDX, [RBP-16]          ; no-arg-parsing entry point
;      8EB:       488D5C24F0       LEA RBX, [RSP-16]
;      8F0:       4883EC18         SUB RSP, 24
;      8F4:       488B7DF8         MOV RDI, [RBP-8]
;      8F8:       488B0591FFFFFF   MOV RAX, [RIP-111]         ; #<FDEFINITION object for NTHCDR>
;      8FF:       B910000000       MOV ECX, 16
;      904:       48892B           MOV [RBX], RBP
;      907:       488BEB           MOV RBP, RBX
;      90A:       FF5009           CALL QWORD PTR [RAX+9]
;      90D:       488B52F9         MOV RDX, [RDX-7]
;      911:       488BE5           MOV RSP, RBP
;      914:       F8               CLC
;      915:       5D               POP RBP
;      916:       C3               RET

NTHと同じようにNTHCDRが呼ばれるようになったようです。

他に、SBCLのELTは、SIMPLE-ARRAYにもDEFTRANSFORMを用意しているようです。

ちなみに、LISPマシンのようなタグアーキテクチャマシンでは、データ型をタグでハードウェア的に判別できたため、汎用のELTも専用のNTHと同じようにオーバーヘッドなしで処理できたようでマニュアルにもそういう説明があります。lispマシンイイ(・ ∀・)

2010-06-29

KMRCLを眺める(169) CONCAT-SYMBOL

| 23:02 | KMRCLを眺める(169) CONCAT-SYMBOL - わだばLisperになる を含むブックマーク はてなブックマーク - KMRCLを眺める(169) CONCAT-SYMBOL - わだばLisperになる

今回は、KMRCLのsymbols.lispからCONCAT-SYMBOLです。

定義は、

(defun concat-symbol (&rest args)
  (apply #'concat-symbol-pkg nil args))

となっています。

前回眺めた、CONCAT-SYMBOL-PKGのパッケージ指定の部分にNILを指定して、カレントパッケージにシンボルをインポートしています。

これを眺めるに、前回のCONCAT-SYMBOL-PKGの名前にPKGとついているのは、どうやら、パッケージも指定できるよ、という意味のように思えました。

動作は、

(KL:CONCAT-SYMBOL :foo '- "bar" :- 'baz)
;⇒ FOO-BAR-BAZ

となっています。

2010-06-28

AUTO-IMPORT

| 22:33 | AUTO-IMPORT - わだばLisperになる を含むブックマーク はてなブックマーク - AUTO-IMPORT - わだばLisperになる

GITHUB-INSTALL便利だし紹介したい!と思って前回のエントリーを書いたのですが、前々回に既に紹介してましたw

あんまりなので、同じく昨日位に作ってみたAUTO-IMPORTを紹介してみます。

TAO/SILENTの論文を読んでパッケージ・パスというアイデアが便利そうだったので、中途半端に真似てみました。

もっと本格的に真似られれば結構便利な気がしますが、下記のコードくらいでも普段の作業では割と便利です。

(DEFPARAMETER *PACKAGE-PATH* 
  (LIST :SHIBUYA.LISP 
        :FARE-UTILS 
        :ALEXANDRIA
        :MYCL-UTIL
        :KMRCL
        :METATILITIES
        ))

(DEFUN AUTO-IMPORT (NAME &AUX ANS)
  (DOLIST (PKG (REVERSE *PACKAGE-PATH*))
    (WHEN (AND (FIND-PACKAGE PKG)
               (FIND-SYMBOL (STRING NAME) PKG))
      (LET ((SYM (INTERN (STRING NAME) PKG)))
        (SHADOWING-IMPORT SYM)
        (PUSH PKG ANS))))
  ANS)
;; FLATTENが欲しい
(AUTO-IMPORT :FLATTEN)
;⇒ (:SHIBUYA.LISP :ALEXANDRIA :MYCL-UTIL :KMRCL)

(FLATTEN '(1 2 3 4 5 (1 2 (3 (4 ((((5)6))))))))
;⇒ (1 2 3 4 5 1 2 3 4 5 6)

(SYMBOL-PACKAGE 'FLATTEN)
;⇒ #<PACKAGE "SHIBUYA.LISP">

GITHUB-INSTALL

| 22:28 | GITHUB-INSTALL - わだばLisperになる を含むブックマーク はてなブックマーク - GITHUB-INSTALL - わだばLisperになる

なんということもないユーティリティですが、結構便利に使える気がします!

(DEFUN GITHUB-INSTALL (USER-NAME NAME)
  (ASDF-INSTALL:INSTALL
   (FORMAT NIL
           "http://github.com/~A/~A/tarball/master"
           USER-NAME
           NAME)))

使用例:

joachifmさんのcl-mechanizeを導入してみる

(GITHUB-INSTALL "joachifm" "cl-mechanize")
Install where?
1) System-wide install: 
   System in /share/sys/cl/asdf/
   Files in /share/sys/cl/src/ 
2) Personal installation: 
   System in /home/mc/doritos-ubuntu/.sbcl/systems/
   Files in /home/mc/doritos-ubuntu/.sbcl/site/ 
 --> 1
Downloading 3174 bytes from http://download.github.com/joachifm-cl-mechanize-68567a0.tar.gz ...
Installing /home/mc/master.asdf-install-tmp in /share/sys/cl/src/,/share/sys/cl/asdf/
joachifm-cl-mechanize-68567a0/
joachifm-cl-mechanize-68567a0/COPYING
joachifm-cl-mechanize-68567a0/README.md
joachifm-cl-mechanize-68567a0/cl-mechanize.asd
joachifm-cl-mechanize-68567a0/cl-mechanize.lisp
joachifm-cl-mechanize-68567a0/packages.lisp
;; GPGのチェックに答える
; loading system definition from /share/sys/cl/asdf/cl-mechanize.asd into
; #<PACKAGE "ASDF0">
; registering #<SYSTEM :CL-MECHANIZE {100DF3D0E1}> as CL-MECHANIZE
NIL

(GITHUB-INSTALL "joachifm/cl-mechanize")

という形式を受け付けるようにしても良いかもしれません。

2010-06-27

Githubを利用して普段のLISP開発環境を晒してみたらどうか

| 12:05 | Githubを利用して普段のLISP開発環境を晒してみたらどうか - わだばLisperになる を含むブックマーク はてなブックマーク - Githubを利用して普段のLISP開発環境を晒してみたらどうか - わだばLisperになる

Githubにソースを上げるとtarボールにしてダウンロードできるリンクができるのですが、都合の良いことに、asdf-installは、ウェブ上のtarボールのURLを指定してインストールすることが可能です。

割と重宝するのですが、これを利用して、Github上に普段のLISP開発環境を登録したら面白いかもしれないと思いました。

具体的には、普段作業で利用しているのは、大抵、CL-USERパッケージだと思いますが、これを自分のGithubのアカウント名と同じ名でパッケージ化し、Githubに上げます。

Githubを利用しているCLer同士で開発環境を晒し合うと思わぬ発見があったりして面白いことになったりしないかな、というところです。

ASDFでインストールできるように晒す手順

  1. ユーザー名.asd を作成
  2. package.lisp を作成
  3. ユーティリティをファイルに纒める (任意)

1. asdファイルを作成 (ユーザー名.asd)

(asdf:DEFSYSTEM :G000001
  :NAME "g000001"
  :DESCRIPTION "g000001"
  :VERSION "2"
  :COMPONENTS ((:FILE "package") ;パッケージを記述するファイル
               (:FILE "g000001" :DEPENDS-ON ("package"))) ;好きな定義を書くファイル
  :DEPENDS-ON (:SERIES
               :ALEXANDRIA
               :SHIBUYA.LISP ))

2. package.lisp に パッケージ周りを設定 (.lisp)

(DEFPACKAGE :G000001
  (:USE :CL 
        :SHIBUYA.LISP
        :SERIES)
  (:IMPORT-FROM :CL-USER 
                :QUIT)
  (:IMPORT-FROM :ASDF 
                :OOS :LOAD-OP)
  (:IMPORT-FROM :ASDF-INSTALL
                :INSTALL)
  (:IMPORT-FROM :ALEXANDRIA
                :CURRY))

3. ユーティリティ等があれば、DEFSYSTEMで指定

等々とすれば準備完了

便利にASDF-INSTALLできるように、

(DEFUN GITHUB-INSTALL (USER-NAME NAME)
  (ASDF-INSTALL:INSTALL
   (FORMAT NIL
           "http://github.com/~A/~A/tarball/master"
           USER-NAME
           NAME)))

のようなものを定義してみます。

これで、

(github-install "g000001" "g000001")

のようにすると、そのユーザーの設定がパッケージとしてインストールできます。

さらに進めて、起動時にCL-USERの代りに作成したパッケージに切り換えるのも良いかもしれません(自分はそうしています)

しかし、問題は、こういう形式で晒している人をどうやってみつけるか、ですねー。

2010-06-26

CLで学ぶ「プログラミングGauche」 (9.8)

| 14:35 | CLで学ぶ「プログラミングGauche」 (9.8) - わだばLisperになる を含むブックマーク はてなブックマーク - CLで学ぶ「プログラミングGauche」 (9.8) - わだばLisperになる

このブログの以前のエントリーを眺めていたら CLで学ぶ「プログラミングGauche」 というのも続き物としてやっていたことを思い出しました。

実に2年ぶりですが、前回9.7章だったので、9.8から突然再開してみます。

前回: CLで学ぶ「プログラミングGauche」 (9.7) - わだばLisperになる - cadr group

9.8 グラフ

リストでグラフを表現する方法。

SchemeもCommon Lispもデータ構造の基本はリストですね。

9.9 具象と抽象の往復

とりあえず試行錯誤して作ってゆくという場合に用いるデータ構造として、リストというのは柔軟で便利、という教え。

古来からLISPは試行錯誤するプログラミングに強いと言われて来ましたが、リストというデータ構造もまたそういうスタイルに貢献しているのかなと思いました。

2010-06-25

KMRCLを眺める(168) CONCAT-SYMBOL-PKG

| 21:54 | KMRCLを眺める(168) CONCAT-SYMBOL-PKG - わだばLisperになる を含むブックマーク はてなブックマーク - KMRCLを眺める(168) CONCAT-SYMBOL-PKG - わだばLisperになる

今回は、KMRCLのsymbols.lispからCONCAT-SYMBOL-PKGです。

定義は、

(defun concat-symbol-pkg (pkg &rest args)
  (declare (dynamic-extent args))
  (flet ((stringify (arg)
           (etypecase arg
             (string
              (string-upcase arg))
             (symbol
              (symbol-name arg)))))
    (let ((str (apply #'concatenate 'string (mapcar #'stringify args))))
      (nth-value 0 (intern (string-default-case str)
                           (if pkg pkg *package*))))))

となっていて、定義と名前からするに、文字列指示子を受け取って文字列が合成されたシンボルを作成するもののようです。

パッケージを指定する機能もあります。

(KL:CONCAT-SYMBOL-PKG NIL "foo" "bar")
;⇒ FOOBAR

(KL:CONCAT-SYMBOL-PKG :KEYWORD "foo" "bar")
;⇒ :FOOBAR

(KL:CONCAT-SYMBOL-PKG :KL "foo" "bar")
;⇒ KMRCL::FOOBAR

pkgにNILを指定するとカレントパッケージが利用されます。

2010-06-24

(30)日米並列Lispワークショップに参加して(1989)

| 21:36 | (30)日米並列Lispワークショップに参加して(1989) - わだばLisperになる を含むブックマーク はてなブックマーク - (30)日米並列Lispワークショップに参加して(1989) - わだばLisperになる

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

です。

本文は、今から21年前の1989年に東北大学で開催された日米並列Lispワークショップのレポートです。

最近では、プロセッサの速度向上が頭打ちになりつつあり、GPGPU等を利用した並列コンピューティングが熱くなりつつありますが、LISP界では、大体、25年前から15年前あたりまで並列計算が熱かったようです。

代表的なところでは、超並列プロセッサのConnection Machineで稼動する *Lispや、Connection Machine Lisp(完成しなかった様子)がありますが、このレポートを読むと、*Lisp以外にも様々な処理系があったことが分かります。

このワークショップで発表された処理系だけでも、

  1. Multilisp(Schemeの拡張)
  2. Mul-T(Tの拡張)
    • メモリ共有型ハードウェアで稼動。future機能
  3. QLisp
    • メモリ共有型ハードウェア
  4. TOP-1 Common Lisp
    • KCLを拡張したもの。future。明示的プロセス生成あり。
  5. PaiLisp
    • Schemeを並列拡張
  6. Concurrent Scheme
  7. mUtiLisp
  8. MultiScheme
  9. TAO
  10. ABCL/R
    • 並列自己反映オブジェクト指向LISP
  11. ABCL/1
  12. PMLisp
  13. Lispマシン EVLIS

などなどかなり多様です。

並列コンピューティングが身近になりつつある今、また並列LISPが身近になることがあるやもしれません!

2010-06-23

KMRCLを眺める(167) STRING-DEFAULT-CASE

| 13:19 | KMRCLを眺める(167) STRING-DEFAULT-CASE - わだばLisperになる を含むブックマーク はてなブックマーク - KMRCLを眺める(167) STRING-DEFAULT-CASE - わだばLisperになる

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

定義は、

;;; Symbol functions

(eval-when (:compile-toplevel :load-toplevel :execute)
  (when (char= #\a (schar (symbol-name '#:a) 0))
    (pushnew :kmrcl-lowercase-reader *features*))
  (when (not (string= (symbol-name '#:a)
                      (symbol-name '#:A)))
    (pushnew :kmrcl-case-sensitive *features*)))

(defun string-default-case (str)
  #+(and (not kmrcl-lowercase-reader)) (string-upcase str)
  #+(and kmrcl-lowercase-reader) (string-downcase str))

というものなのですが、文字列を処理系のデフォルトケース応じて変換するもののようです。

デフォルトケースの判定には、:KMRCL-LOWERCASE-READERが、*FEATURES*にあるかどうかを判定しています。

動作は、

(KL::STRING-DEFAULT-CASE "foo")
;⇒ "FOO"

というところ

2010-06-22

(29)AIP-LISP : (1)レジスタ・アロケータ(1989)

| 12:46 | (29)AIP-LISP : (1)レジスタ・アロケータ(1989) - わだばLisperになる を含むブックマーク はてなブックマーク - (29)AIP-LISP : (1)レジスタ・アロケータ(1989) - わだばLisperになる

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

です。

AIP-LISPとは、東芝が作成していたCommon Lisp処理系で(時代からしてCLtL1)、

AS3000というSun-3を日本語機能を強化したワークステーションにAI処理専用のプロセッサを付けた構成で稼動していた処理系だったようです。

そしてAIPとは、AIプロセッサの略のようで、RISC風なタグアーキテクチャだったようです。

本文では、そのAIPでの変数のレジスタ割付けについて書かれています。

どうも80年代後半はCommon Lisp処理系の実装が熱い時代だったようです。

2010-06-21

KMRCLを眺める(166) CL-SYMBOLS

| 13:37 | KMRCLを眺める(166) CL-SYMBOLS - わだばLisperになる を含むブックマーク はてなブックマーク - KMRCLを眺める(166) CL-SYMBOLS - わだばLisperになる

今回は、KMRCLのsymbols.lispからCL-SYMBOLSです。

前回/前々回のCL-VARIABLESと、CL-FUNCTIONSの結果を合体させたものです。

定義は、

(defun cl-symbols ()
  (append (cl-variables) (cl-functions)))

です。

(LENGTH (KL::CL-SYMBOLS))
;⇒ 868

(KL::CL-SYMBOLS)
;⇒ (*ERROR-OUTPUT* CALL-ARGUMENTS-LIMIT *PRINT-BASE* MOST-NEGATIVE-SINGLE-FLOAT
....
 FILL-POINTER DOLIST)

CLパッケージのシンボルって870もあるんですね。

2010-06-20

(28)電子メール討論 : Common Lisp における実例(1987)

| 19:57 | (28)電子メール討論 : Common Lisp における実例(1987) - わだばLisperになる を含むブックマーク はてなブックマーク - (28)電子メール討論 : Common Lisp における実例(1987) - わだばLisperになる

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

です。

Common Lisp言語の仕様は1981年ごろからメーリングリストを利用して行なわれていたようです。

今でこそ電子メールは当たり前になっていますが、1981年といえば時代を相当先取りしていたのではないかと思います。

討論の方法は、特に進行役は立てず、流れるままに行ない、必要があれば調停役が調整、という感じだったとのこと。

時代が時代だけに転送量が問題だったらしく仕様変更の提案に議論が白熱してメールサーバーがパンクすることもあったようです。

2010-06-19

KMRCLを眺める(165) CL-FUNCTIONS

| 14:49 | KMRCLを眺める(165) CL-FUNCTIONS - わだばLisperになる を含むブックマーク はてなブックマーク - KMRCLを眺める(165) CL-FUNCTIONS - わだばLisperになる

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

前回は、変数のシンボル一覧でしたが、今回は、関数のシンボル一覧のようです。

定義は、

(defun cl-functions ()
  (let ((funcs '()))
    (do-symbols (s 'common-lisp)
      (multiple-value-bind (sym status)
        (find-symbol (symbol-name s) 'common-lisp)
        (when (and (or (eq status :external)
                       (eq status :internal))
                   (fboundp sym))
          (push sym funcs))))
    (nreverse funcs)))

となっていて動作は、

(KL::CL-FUNCTIONS)
;⇒
(DOCUMENTATION PEEK-CHAR UNLESS ENSURE-DIRECTORIES-EXIST 
 FORMAT NSET-DIFFERENCE
 CADADR LABELS TYPE-ERROR-DATUM KEYWORDP FILE-STRING-LENGTH
 LOAD-LOGICAL-PATHNAME-TRANSLATIONS COUNT-IF-NOT ENDP AND LOGORC2
 ADJUSTABLE-ARRAY-P CIS SUBSTITUTE-IF-NOT SYMBOL-PACKAGE
 GET-MACRO-CHARACTER SUBSTITUTE FUNCALL FIND-RESTART REMOVE WRITE
 ECASE CHAR-NOT-GREATERP DEFINE-COMPILER-MACRO FILE-NAMESTRING
 PPRINT-INDENT FILE-ERROR-PATHNAME NULL REMOVE-METHOD ARRAYP
 DESTRUCTURING-BIND COMPILE LOAD STREAM-ERROR-STREAM LOOP
 LISP-IMPLEMENTATION-TYPE FLOAT-DIGITS SET NTH-VALUE
 COMPILER-MACRO-FUNCTION RESTART-CASE CADDDR PPRINT FMAKUNBOUND
 BYTE-SIZE CODE-CHAR WHEN MACHINE-INSTANCE PROG* LIST
 HASH-TABLE-REHASH-THRESHOLD CAADR PATHNAME-NAME TRUNCATE STRING>
 SYMBOL-FUNCTION RASSOC-IF-NOT CHAR ATOM LIST-ALL-PACKAGES LCM 1+
 PACKAGE-USED-BY-LIST FLOAT-SIGN QUOTE CHAR/= LIST* NINTH CDADDR
 CEILING GET READ ECHO-STREAM-OUTPUT-STREAM DEFVAR
 INTEGER-DECODE-FLOAT VECTOR-PUSH-EXTEND PACKAGE-ERROR-PACKAGE
 EQUAL BIT-ANDC2 SOFTWARE-VERSION SLOT-VALUE COPY-READTABLE PROG2
 OR REALP LDB-TEST NSUBSTITUTE NAMESTRING DEFSETF ALPHANUMERICP
 DECF FILE-AUTHOR INTEGERP MAKE-INSTANCES-OBSOLETE
 INVOKE-DEBUGGER SHORT-SITE-NAME FIND-IF COMPILE-FILE-PATHNAME
 LONG-SITE-NAME MAKE-CONDITION REPLACE GETHASH SXHASH REST
 FTRUNCATE PPRINT-TABULAR TENTH STRING-DOWNCASE PPRINT-TAB
 BIT-ORC1 NOTEVERY OUTPUT-STREAM-P SUBST ED FLOOR COPY-SYMBOL
 ASSERT METHOD-COMBINATION-ERROR STRING-LEFT-TRIM USE-VALUE
 MAKE-DISPATCH-MACRO-CHARACTER PROBE-FILE + CDADAR REQUIRE
 COUNT-IF READTABLEP SUBLIS DO-EXTERNAL-SYMBOLS STRING>=
 PRINT-NOT-READABLE-OBJECT CDAR POSITION-IF
 UPDATE-INSTANCE-FOR-DIFFERENT-CLASS LOAD-TIME-VALUE YES-OR-NO-P
 CAR BROADCAST-STREAM-STREAMS PRINT-UNREADABLE-OBJECT ROOM
 CHAR-LESSP DIRECTORY HANDLER-BIND NOT BIT-ORC2 COMPLEX IMPORT
 TIME FDEFINITION < MEMBER-IF-NOT COMPILE-FILE FLET
 SET-EXCLUSIVE-OR REMF * SCALE-FLOAT CAAR MAPCON MAKE-PATHNAME
 UNUSE-PACKAGE COPY-PPRINT-DISPATCH STRING-NOT-EQUAL ATANH
 LOGICAL-PATHNAME-TRANSLATIONS READ-PRESERVING-WHITESPACE CADAAR
 MAKE-ECHO-STREAM SOME PATHNAME-DIRECTORY PSETF
 WITH-COMPILATION-UNIT DIGIT-CHAR LDIFF ARITHMETIC-ERROR-OPERANDS
 APPEND LISTP INTERSECTION MAKE-STRING REINITIALIZE-INSTANCE
 CAADDR ISQRT FRESH-LINE SET-PPRINT-DISPATCH PATHNAME-MATCH-P
 NSTRING-UPCASE PPRINT-FILL SLOT-MISSING CDDADR FILE-WRITE-DATE
 CLRHASH WITH-OPEN-STREAM ASINH FUNCTION-KEYWORDS MEMBER DEFUN
 MAKUNBOUND COPY-TREE SVREF LOGTEST RATIONALP CONJUGATE
 RESTART-NAME ECHO-STREAM-INPUT-STREAM PPRINT-LINEAR
 GET-UNIVERSAL-TIME WRITE-SEQUENCE CONTINUE FIND-IF-NOT
 WITH-OPEN-FILE ARRAY-IN-BOUNDS-P GENTEMP SIMPLE-STRING-P
 ROW-MAJOR-AREF CDAADR HASH-TABLE-REHASH-SIZE
 USER-HOMEDIR-PATHNAME APPLY PATHNAME-TYPE WITH-OUTPUT-TO-STRING
 ARRAY-DIMENSION CONCATENATED-STREAM-STREAMS HASH-TABLE-P
 MULTIPLE-VALUE-LIST FILE-POSITION EQ DEFCONSTANT NSUBSTITUTE-IF
 MAKE-SEQUENCE PPRINT-LOGICAL-BLOCK COUNT DEFINE-CONDITION
 MAKE-SYMBOL BIT ARRAY-ELEMENT-TYPE GET-DECODED-TIME MAX LOGNAND
 GO SUBSETP ARRAY-RANK LOWER-CASE-P RASSOC READ-FROM-STRING
 MEMBER-IF INCF WITH-SLOTS VALUES EVENP CDDDDR
 ENCODE-UNIVERSAL-TIME DELETE-PACKAGE NOTANY CHARACTER NUMBERP
 LOGNOT NTH ETYPECASE PACKAGE-NAME DEFMACRO RANDOM-STATE-P
 DENOMINATOR SUBST-IF MUFFLE-WARNING ALLOCATE-INSTANCE
 CHAR-DOWNCASE TAGBODY PRINC-TO-STRING REVERSE LET SIGNAL
 LIST-LENGTH BLOCK POSITION-IF-NOT GET-PROPERTIES
 UPGRADED-ARRAY-ELEMENT-TYPE DELETE-FILE SINH CCASE
 TRANSLATE-PATHNAME CHAR-EQUAL IMAGPART TAN DELETE-IF-NOT
 SHARED-INITIALIZE ASSOC CTYPECASE WITH-CONDITION-RESTARTS ACOSH
 WITH-PACKAGE-ITERATOR EVAL-WHEN ARRAY-HAS-FILL-POINTER-P
 FUNCTION-LAMBDA-EXPRESSION SLOT-EXISTS-P
 DEFINE-METHOD-COMBINATION CDAAAR READ-CHAR-NO-HANG
 SIMPLE-CONDITION-FORMAT-CONTROL STRING< REDUCE WITH-ACCESSORS
 DIGIT-CHAR-P RATIONAL WRITE-STRING FLOAT-PRECISION
 LISP-IMPLEMENTATION-VERSION LOGANDC2 NUNION
 GET-DISPATCH-MACRO-CHARACTER SETQ NREVERSE ASH
 COMPILED-FUNCTION-P DO* THE COMPLEXP DO-SYMBOLS
 MAKE-CONCATENATED-STREAM GETF >= CONCATENATE IGNORE-ERRORS
 COERCE RATIONALIZE ACONS READ-DELIMITED-LIST WARN
 DELETE-DUPLICATES 1- PPRINT-NEWLINE FLOAT-RADIX
 MAKE-LOAD-FORM-SAVING-SLOTS STRING-NOT-GREATERP CHAR-NOT-EQUAL
 SHADOW ASSOC-IF PRIN1 PRINC ELT ABORT ODDP ASIN / SEARCH SIGNUM
 MAP-INTO FIND-PACKAGE PPRINT-EXIT-IF-LIST-EXHAUSTED REMHASH
 CADAR CHAR-NAME TERPRI WRITE-CHAR EQL CDDR ZEROP MAKE-HASH-TABLE
 MULTIPLE-VALUE-BIND MACROLET PROVIDE MAKE-STRING-OUTPUT-STREAM
 CATCH BIT-XOR LOOP-FINISH > DECODE-FLOAT COPY-LIST
 NSET-EXCLUSIVE-OR PROG STREAM-EXTERNAL-FORMAT POSITION FLOAT
 DEFPARAMETER LOGICAL-PATHNAME CAAAR CHAR-UPCASE NAME-CHAR
 MAKE-LOAD-FORM UNTRACE MAKE-INSTANCE ARRAY-DISPLACEMENT
 SYNONYM-STREAM-SYMBOL WITH-HASH-TABLE-ITERATOR BIT-EQV
 CHARACTERP CLASS-OF BIT-AND TRACE REM MAPCAR CHAR<=
 GET-SETF-EXPANSION STRING<= LOG PPRINT-DISPATCH LOGEQV UNEXPORT
 COMPUTE-APPLICABLE-METHODS WRITE-BYTE DECLAIM FINISH-OUTPUT
 CHAR-NOT-LESSP FUNCTION PACKAGE-SHADOWING-SYMBOLS CLEAR-INPUT
 BIT-IOR ERROR SIMPLE-BIT-VECTOR-P UNWIND-PROTECT DESCRIBE-OBJECT
 READ-SEQUENCE LOGANDC1 MACHINE-VERSION RETURN-FROM EQUALP COS
 MOD BOTH-CASE-P MAKE-BROADCAST-STREAM PUSHNEW PATHNAME
 TREE-EQUAL LDB SOFTWARE-TYPE TAILP CADDR READ-CHAR MISMATCH POP
 STRING-NOT-LESSP NSTRING-DOWNCASE VALUES-LIST CAAADR FIND-CLASS
 RASSOC-IF DIRECTORY-NAMESTRING CLOSE MERGE-PATHNAMES SORT
 NSUBLIS CONSP FIND-SYMBOL NBUTLAST EXP SCHAR CDR DESCRIBE TANH
 UPDATE-INSTANCE-FOR-REDEFINED-CLASS SQRT SHADOWING-IMPORT CERROR
 ENOUGH-NAMESTRING MAPLIST DEFSTRUCT DEFGENERIC READTABLE-CASE
 IN-PACKAGE BOOLE WRITE-TO-STRING GENSYM IDENTITY ROTATEF
 SPECIAL-OPERATOR-P SIN NTHCDR STRING-TRIM EXPT SECOND DPB
 STRING= STRING PRINT-OBJECT Y-OR-N-P NO-NEXT-METHOD DOTIMES
 COMPUTE-RESTARTS SET-DIFFERENCE LOGCOUNT NO-APPLICABLE-METHOD
 CHAR>= CDDAAR MAPL LOGAND MINUSP RENAME-FILE PATHNAMEP
 SET-SYNTAX-FROM-CHAR DELETE-IF TRUENAME MERGE LOGORC1
 MULTIPLE-VALUE-SETQ LET* BIT-NOR LOCALLY SYMBOL-MACROLET NRECONC
 INTERN IF COSH DEFMETHOD STRING-GREATERP INPUT-STREAM-P
 PATHNAME-VERSION BREAK WILD-PATHNAME-P NCONC FFLOOR REMPROP
 CDADR UNION INSPECT MACROEXPAND-1 INTEGER-LENGTH SLEEP
 VECTOR-PUSH LOGNOR CHAR> DEFINE-SYMBOL-MACRO PUSH OPEN-STREAM-P
 PROG1 RETURN UPGRADED-COMPLEX-PART-TYPE
 TWO-WAY-STREAM-INPUT-STREAM - ATAN SHIFTF LAMBDA
 SET-MACRO-CHARACTER PATHNAME-HOST MAPHASH CHAR-INT NSUBST-IF
 DEFINE-SETF-EXPANDER WRITE-LINE SETF MAPC RPLACA FILL
 MULTIPLE-VALUE-CALL TYPE-OF CDDDAR DRIBBLE CHANGE-CLASS CHAR<
 ROUND PAIRLIS THROW MACROEXPAND SIMPLE-VECTOR-P CONSTANTLY PHASE
 WITH-INPUT-FROM-STRING APROPOS SLOT-BOUNDP CLEAR-OUTPUT TYPEP
 BIT-NOT MULTIPLE-VALUE-PROG1 STEP ENSURE-GENERIC-FUNCTION
 STREAMP FOURTH SYMBOLP SET-DISPATCH-MACRO-CHARACTER STRING-LESSP
 VECTOR NSUBST SYMBOL-NAME BOUNDP FUNCTIONP CASE FLOATP
 REMOVE-DUPLICATES MAKE-STRING-INPUT-STREAM MACHINE-TYPE MIN
 SUBSEQ STRINGP ADJOIN TRANSLATE-LOGICAL-PATHNAME PSETQ
 PPRINT-POP STRING-RIGHT-TRIM FIND-ALL-SYMBOLS
 GET-OUTPUT-STREAM-STRING CAAAAR BYTE HASH-TABLE-TEST
 SUBST-IF-NOT INVOKE-RESTART-INTERACTIVELY DO PACKAGE-USE-LIST
 UPPER-CASE-P STABLE-SORT HOST-NAMESTRING STANDARD-CHAR-P
 DO-ALL-SYMBOLS EIGHTH OPEN READ-BYTE HANDLER-CASE FORMATTER
 PACKAGE-NICKNAMES ARITHMETIC-ERROR-OPERATION REMOVE-IF
 BYTE-POSITION COPY-SEQ RESTART-BIND GET-INTERNAL-RUN-TIME THIRD
 CAADAR NSUBSTITUTE-IF-NOT PROCLAIM MAPCAN MAKE-SYNONYM-STREAM
 VECTORP LOGXOR = UNBOUND-SLOT-INSTANCE PRINT NINTERSECTION
 SIMPLE-CONDITION-FORMAT-ARGUMENTS GCD DEFINE-MODIFY-MACRO
 FCEILING TYPECASE CALL-METHOD FORCE-OUTPUT CADR ARRAY-TOTAL-SIZE
 UNREAD-CHAR PATHNAME-DEVICE STRING/= REMOVE-IF-NOT EXPORT
 SLOT-MAKUNBOUND <= PROGN NUMERATOR REALPART DEFCLASS CONS
 HASH-TABLE-COUNT GRAPHIC-CHAR-P PACKAGEP ALPHA-CHAR-P
 MAKE-RANDOM-STATE LISTEN STRING-UPCASE CADDAR COPY-ALIST SIXTH
 REVAPPEND SYMBOL-VALUE SEVENTH DISASSEMBLE COND SBIT
 TYPE-ERROR-EXPECTED-TYPE BIT-ANDC1 PARSE-INTEGER LOGIOR
 MAKE-ARRAY BIT-NAND INTERACTIVE-STREAM-P BIT-VECTOR-P
 SLOT-UNBOUND APROPOS-LIST FBOUNDP NSTRING-CAPITALIZE
 WITH-SIMPLE-RESTART AREF ASSOC-IF-NOT COMPLEMENT PROGV FROUND
 ARRAY-ROW-MAJOR-INDEX MAKE-TWO-WAY-STREAM STRING-EQUAL
 NSUBST-IF-NOT PLUSP EVERY STREAM-ELEMENT-TYPE CONSTANTP
 FIND-METHOD DELETE CDDAR FILE-LENGTH PARSE-NAMESTRING
 MAKE-PACKAGE READ-LINE DEPOSIT-FIELD ABS RENAME-PACKAGE
 CHECK-TYPE INVOKE-RESTART HASH-TABLE-SIZE USE-PACKAGE RANDOM
 PRIN1-TO-STRING LAST TWO-WAY-STREAM-OUTPUT-STREAM
 ARRAY-DIMENSIONS WITH-STANDARD-IO-SYNTAX MACRO-FUNCTION CHAR=
 LOGBITP UNINTERN COPY-STRUCTURE MASK-FIELD VECTOR-POP
 SYMBOL-PLIST CHAR-CODE METHOD-QUALIFIERS ADJUST-ARRAY DEFPACKAGE
 CDDDR INVALID-METHOD-ERROR CELL-ERROR-NAME CLASS-NAME RPLACD
 CHAR-GREATERP MAKE-LIST INITIALIZE-INSTANCE STRING-CAPITALIZE
 MAP STORE-VALUE ADD-METHOD ACOS FIFTH SUBTYPEP DEFTYPE BUTLAST
 LENGTH /= EVAL CDAAR DECODE-UNIVERSAL-TIME
 GET-INTERNAL-REAL-TIME FIND SUBSTITUTE-IF FIRST FILL-POINTER
 DOLIST)

2010-06-18

Getting Started in *LISP (27)

| 23:50 | Getting Started in *LISP (27) - わだばLisperになる を含むブックマーク はてなブックマーク - Getting Started in *LISP (27) - わだばLisperになる

今回は、4.3章 *Lisp Error Checking です。

4.3 *Lisp Error Checking

*Lispには、 *interpreter-safety* という変数があり現在のエラーチェックの度合いを設定したり確認したりできるとのこと。

度合いは、0〜3の整数で表わされ、

0 実行時のエラーチェックは無効

1 最小限の実行時エラーチェックだけ有効。コードのどの位置でエラーが起きたかの通知は不正確かもしれない

2 将来の拡張のための予約

3 実行時エラーチェックが全て有効。

そして、処理系のデフォルトは3。

この値を変更するときには、

(setq *interpreter-safety* 3)

とする。

大まかにいって、3はフルにエラーチェック、0はチェックなし。

デバッグの時には、3を利用し、一度正しくプログラムが走ることが確認できれば0にしてスピードを上げる、というような使い方ができる。

(でき得る限りのスピードを出すということになると型宣言+コンパイルということになる。この辺りは、5章で解説)

レベル1は、主にほぼ完全に動くコードをテストするのに使える。

エラーの内容は正確だけれど、実際にエラーを起こしている場所とエラーが起きるタイミングが異なることがある。

> (setq *interpreter-safety* 1)

> (/!! 3 0)	;; The error occurs here, but is not signaled...
#<FLOAT-Pvar 5-32 *DEFAULT-VP-SET* (32 16)>

> (+!! 2 3)	;; Still not reading a value from the CM...
#<FIELD-Pvar 11-3 *DEFAULT-VP-SET* (32 16)>

> (*sum 1)	;; Upon reading a value, the error is signaled:
>>Error: The result of a (two argument) float /!! overflowed
CMI::WAIT-UNTIL-FEBI-OUTPUT-FIFO-NOT-EMPTY:
:A  0: Abort to Lisp Top Level
->

のような場合、(*sum 1)で実際に値を読み込んだときにエラーが起きたりする。

ちなみに、シミュレーターの場合の動作では、どうやら実質3にしか設定されなさそうな様子。

次回、4.4から再開です。

2010-06-17

(27)マルチパラダイム言語処理系MCによるプログラム開発(1990)

| 21:00 | (27)マルチパラダイム言語処理系MCによるプログラム開発(1990) - わだばLisperになる を含むブックマーク はてなブックマーク - (27)マルチパラダイム言語処理系MCによるプログラム開発(1990) - わだばLisperになる

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

です。

このMCという処理系は、Meta Computing environmentの略だそうで、LISPとPrologを融合した処理系だそうです。

LISPとPrologの融合というと有名なところではTAOがありますが、MCの融合の方針は、手続き的な記述の方が楽に書けるところは、LISPスタイルで記述、宣言的な記述だと上手く書ける場合は、Prologスタイルで書く、というように書き分けつつ共存する、というもののようです。

具体的にどういう風に共存しているかですが、Prolog側は、Uranus(Prolog/KR)のようにS式で記述。

関数の定義は、CLと同じく、DEFUN、Prologの述語の定義は、DEFPREDICATEという風にし、LISPからProlog側を呼ぶには、(?-)、(?ALL)等の?から始まるフォームを利用し、逆にPrologからLISPを呼ぶには、(IS)や、(ARE)を使うとのこと。

また、開発事例として、MC/LISPコンパイラを挙げいて、コンパイラの場合、パターンマッチを活用できるためPrologを主体とし、Prologで処理しにくいところはLISPで記述、という風にお互いを補いつつ効率的に記述できたとのことです。

LISPとPrologが融合した処理系がTAOの他にあったとは意外でした。

2010-06-16

KMRCLを眺める(164) CL-VARIABLES

| 14:05 | KMRCLを眺める(164) CL-VARIABLES - わだばLisperになる を含むブックマーク はてなブックマーク - KMRCLを眺める(164) CL-VARIABLES - わだばLisperになる

functions.lispも終了したので、今回からは、KMRCLのsymbols.lisp眺めることにしました。

ということで、symbols.lispから CL-VARIABLES です。

定義を眺める限りでは、CLパッケージの中から変数が束縛されたシンボルを抜き出すもののようです。

(defun cl-variables ()
  (let ((vars '()))
    (do-symbols (s 'common-lisp)
      (multiple-value-bind (sym status)
          (find-symbol (symbol-name s) 'common-lisp)
        (when (and (or (eq status :external)
                       (eq status :internal))
                   (boundp sym))
          (push sym vars))))
    (nreverse vars)))

動作は、

(KL:CL-VARIABLES)
;⇒ 
(*ERROR-OUTPUT* CALL-ARGUMENTS-LIMIT *PRINT-BASE* MOST-NEGATIVE-SINGLE-FLOAT
 *LOAD-PRINT* *GENSYM-COUNTER* BOOLE-ANDC1 BOOLE-C2 LEAST-NEGATIVE-SINGLE-FLOAT
 ARRAY-TOTAL-SIZE-LIMIT LONG-FLOAT-EPSILON *PRINT-RADIX* *PRINT-CASE*
 LEAST-POSITIVE-NORMALIZED-SHORT-FLOAT ARRAY-RANK-LIMIT +
 LEAST-POSITIVE-DOUBLE-FLOAT *** MOST-NEGATIVE-LONG-FLOAT DOUBLE-FLOAT-EPSILON
 * *LOAD-VERBOSE* CHAR-CODE-LIMIT LEAST-NEGATIVE-LONG-FLOAT
 MOST-POSITIVE-LONG-FLOAT BOOLE-AND BOOLE-ORC2 MOST-NEGATIVE-FIXNUM
 *PRINT-CIRCLE* *RANDOM-STATE* INTERNAL-TIME-UNITS-PER-SECOND *STANDARD-INPUT*
 *COMPILE-FILE-TRUENAME* NIL PI MOST-POSITIVE-DOUBLE-FLOAT
 LEAST-NEGATIVE-NORMALIZED-SINGLE-FLOAT SINGLE-FLOAT-NEGATIVE-EPSILON
 *QUERY-IO* LEAST-NEGATIVE-NORMALIZED-SHORT-FLOAT *LOAD-PATHNAME*
 LEAST-NEGATIVE-SHORT-FLOAT DOUBLE-FLOAT-NEGATIVE-EPSILON BOOLE-NAND
 *PRINT-ARRAY* T *PRINT-LEVEL* *PRINT-GENSYM* MOST-NEGATIVE-SHORT-FLOAT
 BOOLE-C1 *PACKAGE* /// BOOLE-XOR *DEBUG-IO* / +++ // BOOLE-IOR
 LAMBDA-LIST-KEYWORDS MOST-POSITIVE-FIXNUM ** *LOAD-TRUENAME*
 LEAST-POSITIVE-LONG-FLOAT *PRINT-LINES* SINGLE-FLOAT-EPSILON
 LAMBDA-PARAMETERS-LIMIT MOST-POSITIVE-SINGLE-FLOAT *PRINT-LENGTH*
 SHORT-FLOAT-EPSILON *FEATURES* MULTIPLE-VALUES-LIMIT *COMPILE-VERBOSE*
 *COMPILE-PRINT* MOST-NEGATIVE-DOUBLE-FLOAT *READTABLE* *READ-SUPPRESS*
 *PRINT-RIGHT-MARGIN* *MODULES* LEAST-NEGATIVE-DOUBLE-FLOAT
 SHORT-FLOAT-NEGATIVE-EPSILON BOOLE-NOR - BOOLE-ANDC2 *TRACE-OUTPUT*
 *STANDARD-OUTPUT* LEAST-POSITIVE-SINGLE-FLOAT
 LEAST-POSITIVE-NORMALIZED-LONG-FLOAT LEAST-POSITIVE-SHORT-FLOAT BOOLE-2
 LONG-FLOAT-NEGATIVE-EPSILON BOOLE-SET LEAST-POSITIVE-NORMALIZED-SINGLE-FLOAT
 LEAST-NEGATIVE-NORMALIZED-LONG-FLOAT *PRINT-PRETTY* *PRINT-PPRINT-DISPATCH*
 BOOLE-EQV *PRINT-ESCAPE* *PRINT-MISER-WIDTH* *READ-BASE* *PRINT-READABLY*
 *COMPILE-FILE-PATHNAME* ARRAY-DIMENSION-LIMIT *DEBUGGER-HOOK*
 MOST-POSITIVE-SHORT-FLOAT LEAST-NEGATIVE-NORMALIZED-DOUBLE-FLOAT BOOLE-1
 *READ-DEFAULT-FLOAT-FORMAT* ++ *READ-EVAL* BOOLE-ORC1
 LEAST-POSITIVE-NORMALIZED-DOUBLE-FLOAT *TERMINAL-IO* *MACROEXPAND-HOOK*
 *DEFAULT-PATHNAME-DEFAULTS* BOOLE-CLR *BREAK-ON-SIGNALS*)

といったところ。

上のコードを眺めていて、CLパッケージが他を継承していることなんてあるんだろうかと、SBCL/Allegro CL/CCL/XCL/CLISPで CLパッケージ内の :INHERITED を探してみましたが

(let ((vars '()))
  (do-symbols (s 'common-lisp)
    (multiple-value-bind (sym status)
        (find-symbol (symbol-name s) 'common-lisp)
      (when (and (eq status :INHERITED)
                 (boundp sym))
        (push sym vars))))
  (nreverse vars))
;⇒ NIL

でした。

処理系が処理系依存の(CL標準でない)シンボルをCLパッケージにどっかから(CL-INTERNALとかから)継承していたら、:INHERITEDなシンボルがあったりするんでしょうか。

2010-06-15

(26)最近のLisp言語(1993)

| 20:11 | (26)最近のLisp言語(1993) - わだばLisperになる を含むブックマーク はてなブックマーク - (26)最近のLisp言語(1993) - わだばLisperになる

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

です。

最近といっても1993年なので17年前のことになります。

最初にLISPの歴史的なところをざっと紹介して、

LISPの基本的なところを解説。

最近のLISPとして、Common LispとSchemeを紹介しています。

新しいところとして、

  1. タイプ
  2. レキシカル・スコープ
  3. クロージャ
  4. 構造体
  5. パッケージ
  6. オブジェクト指向
  7. ウィンドウ・インターフェイス
  8. 並列機能

を取り上げていて、最後にSchemeの紹介があります。

CLX〜Schemeと他の伝統的なLISP方言との比較等、内容は盛り沢山で、今読んでも面白いと思います。

2010-06-13

KMRCLを眺める(163) COMPOSE

| 14:09 | KMRCLを眺める(163) COMPOSE - わだばLisperになる を含むブックマーク はてなブックマーク - KMRCLを眺める(163) COMPOSE - わだばLisperになる

今回は、KMRCLのfunctions.lispからCOMPOSEです。

COMPOSEは割と有名な関数のようで、CURRY等と同じく色々なライブラリで提供されていることが多いです。

ポール・グレアムのANSI Common Lispでは、Dylanからの引用として紹介されていました。

実際Dylanには標準で用意されていますが、この辺りから広がったのでしょうか。どうでも良いことですが、どの辺りが起源か知りたいです。

動作は、

(MAPCAR (KL:COMPOSE #'INTERN #'STRING-DOWNCASE)
        (LISTQ A B C D))
;⇒ (|a| |b| |c| |d|)

という風に、関数を合体してゆけます。

定義は、

(defun compose (&rest fns)
  (if fns
      (let ((fn1 (car (last fns)))
            (fns (butlast fns)))
        #'(lambda (&rest args)
            (reduce #'funcall fns
                    :from-end t
                    :initial-value (apply fn1 args))))
      #'identity))

という風になっています。

同じCOMPOSEでもライブラリによって定義が違っているので眺めてみると面白いかもしれません。

2010-06-12

(25)動的オブジェクト指向言語Dylan(1995)

| 16:03 | (25)動的オブジェクト指向言語Dylan(1995) - わだばLisperになる を含むブックマーク はてなブックマーク - (25)動的オブジェクト指向言語Dylan(1995) - わだばLisperになる

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

です。

CiNiiにDylan関係のものもあったりしないかなと探してみたら、ありました!

Dylanは、Algol文法を持つLISP系言語として知られていると思いますが、当時、Appleが中心となって開発されていた言語です。

使ってみると、LISP的なところを取り入れた言語というよりも、LISPの見た目をAlgol風にして機能を足したというところで、中身がずばりLISPなのでLISPの人が好むのも分かる気がします。(そもそも初期はS式でも書けました)

Dylanが提案された当時のターゲットとしては、C++や、Cを利用している層で、C++を置き換えることを狙っていたようです。

Common Lisp等と違うところとしては、開発環境と、実行環境が分かれているということが挙げられていて、これは、単体の実行ファイルを配布することが念頭にあった為の様子。

CL(CLOS)の美味しいところをベースに、Rubyの見た目で、単体の実行ファイルを配布できる、という今でも美味しそうな言語ですが、ぱっとしなかったのが残念です(LISPの人には)

今でもopendylan.org等で開発が続けられているので興味のある方は如何でしょうか。

Appleで主力開発言語となっていたならば、iPadでもDylanが動いていたことでしょう…。

2010-06-11

Getting Started in *LISP (26)

| 22:39 | Getting Started in *LISP (26) - わだばLisperになる を含むブックマーク はてなブックマーク - Getting Started in *LISP (26) - わだばLisperになる

今回は、4.2章 Error Messages です。

4.2 Error Messages

エラーについては、警告の場合と同じように様々ある

> (pront 'oops!)
>>Error: The function PRONT is undefined.
SYMBOL-FUNCTION:
   Required arg 0 (S): PRONT
:C  0: Try evaluating #'PRONT again
:A  1: Abort to Lisp Top Level
->

というようなタイプミスにより引き起こされたものから、

> (/!! 3 0)
>>Error: In interpreted /!!.
	The result of a (two argument) float /!! overflowed.
	There are 8192 selected processors,
	8192 processors have an error.
	A SINGLE-FLOAT temporary pvar stored at location 458752
	caused the error.
*LISP-I::/!!-2:
...
:A  : Abort to Lisp Top Level
->

不正な引数を与えて起きたエラー等々。

エラーメッセージがConnection Machineっぽくて良いですね。

4.2.1 Recovering from Errors

エラーから(デバッガから)の復帰は、Lucid CLならば、:a(abort)でOKとのこと。

When You Abort, Remember to (*warm-boot)

しかし、*Lispの場合、Connection Machineとフロントエンドのマシンの二つのマシンを使っているので、フロントエンド側が復帰していてもConnection Machineがうまく復帰していない場合がある。

こういう場合には、

(*warm-boot)

を使う。

(*warm-boot)はConnection Machineの内部状態をリセットし、その他の細々としたことを整えてくれるとのこと。

デバッガから抜けた際には、Connection Machine内が色々と混乱した状態になっている場合もあり、エラーにならない筈のコードもエラーになったりするかもしれない。

> (*sum 1)	;; NOTE: This example was run on an 8K CM
8192

> (*when (evenp!! (self-address!!)) (break))
>>Break: break
EVAL:
 Required arg 0 (EXPRESSION): (*WHEN (EVENP!! (SELF...
:C	0: Return from Break
:A	1: Abort to Lisp Top Level
-> :a
Abort to Lisp Top Level

> (*sum 1)
4096

こんなことになったりするらしい。

ちなみに、シミュレーターでも同じようなことになりました。

上記の例は、(evenp!! (self-address!!))で半分のプロセッサを除外している状態で、BREAK→Abortとしたため、プロセッサが半分しか選択されていない状態が残ってしまっているためらしい。

こういうときには、(*warm-boot)して復帰させる

(*warm-boot)

(*sum 1)
;⇒ 8192
For More Persistent Errors, Try (*cold-boot)

(*warm-boot)しても直らないようなときには、一歩進んで(*cold-boot)する。

(*cold-boot)は(*warm-boot)よりもやりなおし度合いが深い。

また、エラーが永続的なpvarに起因するのではないか、と思われるときは、

(*cold-boot :undefine-all t)

を実行してみると良いとのこと。

:undefine-all tは、すべてのVPセットと、pvarを初期化する。

この初期化に伴い作成したプログラムは再ロードする必要があるかもしれない。

上記の対処方法を試しても謎のエラーがしつこく出る場合は、システム管理者に相談しましょう、とのこと。

次回、4.3から再開です。

2010-06-10

KMRCLを眺める(162) _F

| 20:16 | KMRCLを眺める(162) _F - わだばLisperになる を含むブックマーク はてなブックマーク - KMRCLを眺める(162) _F - わだばLisperになる

今回は、KMRCLのfunctions.lispから_Fです。

実装を眺める限り、_FのFはSETFのFから来ているようです。

(defmacro _f (op place &rest args)
  (multiple-value-bind (vars forms var set access)
                       (get-setf-expansion place)
    `(let* (,@(mapcar #'list vars forms)
            (,(car var) (,op ,access ,@args)))
       ,set)))

という風にGET-SETF-EXPANSIONを使っています

使い方は、APPENDFを例にすると、

(LET ((X (LIST 1 2 3 4)))
  (LISPWORKS:APPENDF X (LIST 10 20 30 40))
  X)
;⇒ (1 2 3 4 10 20 30 40)

というところを

;; APPENDF
(LET ((X (LIST 1 2 3 4)))
  (KL:_F APPEND X (LIST 10 20 30 40))
  X)
;⇒ (1 2 3 4 10 20 30 40)

と書けます。

_Fは、Arcいうzapと同じ動きですね。

;; Arc
(let x (list 1 2 3 4)
  (zap + x (list 10 20 30 40))
  x)
;⇒ (1 2 3 4 10 20 30 40)

TAOにもこういうのがあって、

(let ((x (list 1 2 3 4)))
  (!!append !x (list 10 20 30 40))
  X)
;⇒ (1 2 3 4 10 20 30 40)

と書けます。

TAOは、任意に!で代入先を指示できたりするので、より高機能!

2010-06-09

(24)KCl(Kyoto Common Lisp)(1984)

| 14:20 | (24)KCl(Kyoto Common Lisp)(1984) - わだばLisperになる を含むブックマーク はてなブックマーク - (24)KCl(Kyoto Common Lisp)(1984) - わだばLisperになる

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

です。

KClは国産のCommon Lisp処理系としても、初期からあるCL実装としても世界的に有名かと思います。

今では、KClそのものを使うことはあまり多くないかと思うのですが、ECLや、GCLはKClの系統です。

本文は、そのKClの開発動機と開発について、当時のCL界について等が語られています。

1983年の春に研究所に新しく導入される予定のミニコンでLISP処理系が動いていなかったのと、ちょうどCLtL(Laser版)がほぼ完成しているのを知って、それじゃあ、作ってみようということになったのがKClの初まりだったようですが、本文は、1984の春に書かれていて、CLtLの最新版も完成前のMary Poppins版ということで、KClは、CLtL1より前から存在していたんですね。

当時の状況としては、Spice Lispや、Lispマシンのように既存のLISP処理系が、CL準拠に対応するというのが多かったようなので、Cで一から書かれたというのも異色だったようです。

また、実装についても色々述べられていますが、KClでもインタプリタの速度を重要視していたようです。

等々、他にも色々面白いことが書かれています。

2010-06-08

KMRCLを眺める(161) DEFUN-MEMO

| 13:48 | KMRCLを眺める(161) DEFUN-MEMO - わだばLisperになる を含むブックマーク はてなブックマーク - KMRCLを眺める(161) DEFUN-MEMO - わだばLisperになる

今回は、KMRCLのfunctions.lispからDEFUN-MEMOです。

前回のMEMOIZEを利用していますが、メモワイズ機能を付きのDEFUNというところです。

定義は、

(defmacro defun-memo (fn args &body body)
  "Define a memoized function"
  `(memoize (defun ,fn ,args . ,body)))

になっていて、DEFUNの返り値を使っているというのは珍しいですね。

(KL:DEFUN-MEMO FIB (N)
  (IF (< N 2)
      N
      (+ (FIB (1- N))
         (FIB (- N 2)))))

(FIB 100)
;⇒ 354224848179261915075

DEFUNを置き換えるだけで簡単にメモ化版関数が定義されます。

2010-06-07

(23)新ELISのプログラム開発支援系(1992)

| 19:54 | (23)新ELISのプログラム開発支援系(1992) - わだばLisperになる を含むブックマーク はてなブックマーク - (23)新ELISのプログラム開発支援系(1992) - わだばLisperになる

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

です。

本文では、国産LispマシンのELIS上で稼動していた、ELIS Common Lispの開発支援について述べられています。

  1. インタプリタ環境の重視
  2. 特定のプログラミングパラダイムに依存しない開発支援機能

が柱となる方針で、インタプリタ環境の重視というのは、TAOから受け継がれたもののようですし、プログラミングパラダイムに依存しないというのもProlog + Smalltalk + TAOのかわりにCommon Lispということで、これも受け継いだ特性のようです。

具体的な、支援としては、

  1. 3つの異なったパラダイムでも上手く動く実行追跡機能
  2. データ構造の簡単な表示/変更機能
  3. 3つの異なったパラダイムでも上手く動くデバッガ

実行の追跡については、Common Lispフック機能(ANSI CLではなくなってしまいました)を拡張する形で実装していて、論理型も同じくフックが用意されています。

そういえば、ANSI Common Lispからはなんでevalhook/applyhookが消えてしまったんでしょう。

HyperSpecに書いてあったりするかもしれないので探してみたいところです。

2010-06-06

みんなでLISPのウェブアプリを作る場所が欲しい (2)

| 14:23 | みんなでLISPのウェブアプリを作る場所が欲しい (2) - わだばLisperになる を含むブックマーク はてなブックマーク - みんなでLISPのウェブアプリを作る場所が欲しい (2) - わだばLisperになる

を書いてからぼーっとしているうちに早2週間経過してしまいました。

経過報告

経過報告ですが、

  1. サーバーは、お名前.comのVPSを借りてみました。
  2. とりあえず、 http://cddddr.org (クダダ ダダー)というドメイン名を取得
  3. 適当にGoogle appsを設定(連絡用とかにあると便利かなと思い…)
    1. cddddrのGoogle Sites
  4. SBCLとかちょっとインストール
  5. quekさんに、hunchentoot立ててもらう
  6. とりあえず、 いまさらの common-lisp-users.jp 立ててみる

といったところです、まだまだアプリを立ち上げるまで長い道程な気がします…。

参加するには

利用希望者の追加ですが、Help me, hackers!さん

のユーザー登録システムに丁度SSHの鍵を登録するところがあったりTwitterと連携できるので、Help me, hackers!のアカウントを作成してSSHの鍵を登録したら @g177564 などで @ してもらい、私が作成し次第、返信するという感じで良いかなと考えています。

また、実際にウェブアプリを作成しはじめたらここにタスクを登録できるのでぴったりかなと思っています。

SSHはパスワード認証はなしで鍵認証のみにしてします。

この場合、基本的にユーザー名は、Help me, hackers!(=Twitter)のアカウント名になるので、他の名前を希望される方は、その旨を記載して @ してください。

サーバー費用ですが、色々面倒になってきたので、割り勘は無しで私の自腹にしようかなと思います(もし実際に会う機会でもあればご飯でも奢って下さいw)

管理者権限ですが、必要な場合は @ してください。 アカウントを作成する時でもOKです。

いろいろな制限

お名前.comのVPSは利用できるポートがかなり制限されているようです。

ウェブ関係で基本的に使えるのは80番と、443番だけのようなので

appacheのバーチャルホストの設定で、内部のサーバーに転送するようにしてみています。(例えば、block.cdddddr.org => 内部のhunchentoot:8080番のようになっています)

メモリは1Gしかないので、そんなに立てられないとは思いますが、20ポート分位設定してみました。

募集中

  • common-lisp-users.jpの内容を作成したい方
  • Lispが書きたくてサーバー回りに強い方

以上、進みが遅いですが、興味のある方 @g177564 へのご連絡お待ちしています!

2010-06-05

Getting Started in *LISP (25)

| 11:27 | Getting Started in *LISP (25) - わだばLisperになる を含むブックマーク はてなブックマーク - Getting Started in *LISP (25) - わだばLisperになる

今回から4章です。

3章の最後の前振りによれば、4章は、エラーハンドリングとデバッガの使用方法についての説明とのことでした。

When Things Go Wrong

予期せぬエラーに対してデバッガが教えてくれる情報や、エラー/警告メッセージなどを手掛かりにどう対処してゆくかを解説するのがこの章の目的とのこと

この章のテキストでは、Sun Common Lispのメッセージ表示を使うが、処理系によって表示に違いがあるとのことですが、SunもCLの処理系を出してたんですね。(パッケージ名がlclなので、中身はLucid CLのようですが)

4.1 Warning Messages

警告について

警告メッセージにも色々ありますが、まずは、

;;; GC: 174988 words [699952 bytes] of dynamic storage in use.
;;; 644210 words [2576840 bytes] of free storage available.

のようなGCの警告メッセージから。

これはGCが稼動しているということで、処理系によっては、(setq sys::*gc-silence* t)等で黙らせることができることが解説されています。

今どきの処理系ではCMUCLがGCの稼働状況が激しく表示されますが、これも(setq *gc-verbose* nil)で静かにできるようです。

次に、

> (defun simple (x) (+!! x 2))
> (compile 'simple)
;;; Warning: *Lisp Compiler: While compiling function SIMPLE:
;;;          The expression (+!! X 2) is not compiled because
;;;          the compiler cannot find a declaration for X.

のようなもので、コンパイラがすべてをコンパイルするのには情報が足りなかったため部分的にコンパイルできなかったというようなメッセージ。

可能な限り効率的というわけではないけれど、関数はコンパイルできているというもので、こういった類のメッセージは、無視できる。

後の*Lispコンパイラの章で詳しく解説するとのこと。

次回、4.2のエラーメッセージの解説から再開です。

2010-06-04

KMRCLを眺める(160) MEMOIZE

| 07:55 | KMRCLを眺める(160) MEMOIZE - わだばLisperになる を含むブックマーク はてなブックマーク - KMRCLを眺める(160) MEMOIZE - わだばLisperになる

今回は、KMRCLのfunctions.lispからMEMOIZEです。

前回のMEMO-PROCを利用して既存の関数をメモ化版にするものです。

定義は、

(defun memoize (fn-name)
  (setf (fdefinition fn-name) (memo-proc (fdefinition fn-name))))

動作は、

(DEFUN FIB (N)
  (IF (< N 2)
      N
      (+ (FIB (1- N))
         (FIB (- N 2)))))

;; トレース
(TRACE FIB)

(FIB 5)
0: (FIB 5)
  1: (FIB 4)
    2: (FIB 3)
      3: (FIB 2)
        4: (FIB 1)
        4: FIB returned 1
        4: (FIB 0)
        4: FIB returned 0
      3: FIB returned 1
      3: (FIB 1)
      3: FIB returned 1
    2: FIB returned 2
    2: (FIB 2)
      3: (FIB 1)
      3: FIB returned 1
      3: (FIB 0)
      3: FIB returned 0
    2: FIB returned 1
  1: FIB returned 3
  1: (FIB 3)
    2: (FIB 2)
      3: (FIB 1)
      3: FIB returned 1
      3: (FIB 0)
      3: FIB returned 0
    2: FIB returned 1
    2: (FIB 1)
    2: FIB returned 1
  1: FIB returned 2
0: FIB returned 5
;⇒ 5

;; メモ化発動
(KL:MEMOIZE 'FIB)

(FIB 5)
0: (FIB 5)
  1: (FIB 4)
    2: (FIB 3)
      3: (FIB 2)
        4: (FIB 1)
        4: FIB returned 1
        4: (FIB 0)
        4: FIB returned 0
      3: FIB returned 1
      3: (FIB 1)
      3: FIB returned 1
    2: FIB returned 2
    2: (FIB 2)
    2: FIB returned 1
  1: FIB returned 3
  1: (FIB 3)
  1: FIB returned 2
0: FIB returned 5
;⇒ 5

といったところで、FIBをメモ化すると関数の呼び出しが減るのが分かると思います。

2010-06-03

(22)LISP 構造エディタ(<特集>エディタ)(1984)

| 07:17 | (22)LISP 構造エディタ(エディタ)(1984) - わだばLisperになる を含むブックマーク はてなブックマーク - (22)LISP 構造エディタ(エディタ)(1984) - わだばLisperになる

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

です。

近頃のエディタといえば、LISPの編集でも普通のテキストエディタ+S式編集支援機能という感じですが、80年代位には、構造化エディタというS式単位で編集するエディタもあったようです。

Interlisp等が代表格らしいのですが、本文では、EMACSはちらっと紹介するに留まり、Interlispのエディタを中心に紹介しています。

大体の動作も想像できるほど、かなり詳細に紹介されていますので、構造エディタを詳しく知りたい人には良い資料かなと思いました。

2010-06-02

KMRCLを眺める(159) MEMO-PROC

| 07:56 | KMRCLを眺める(159) MEMO-PROC - わだばLisperになる を含むブックマーク はてなブックマーク - KMRCLを眺める(159) MEMO-PROC - わだばLisperになる

ifstar.lispの次のファイルということで、今回は、KMRCLのfunctions.lispからMEMO-PROCです。

MEMO-PROCはをメモワイズ関数化する関数です。

定義は、

(defun memo-proc (fn)
  "Memoize results of call to fn, returns a closure with hash-table"
  (let ((cache (make-hash-table :test #'equal)))
    #'(lambda (&rest args)
        (multiple-value-bind (val foundp) (gethash args cache)
          (if foundp
              val
            (setf (gethash args cache) (apply fn args)))))))

となっています。

引数とその結果が登録されたハッシュ表を引き、結果が既に登録されていれば、その値を返し、なければ計算というしくみで、割と定番かと思います。

動作は、

(DEFUN FIB (N)
  (IF (< N 2)
      N
      (+ (FIB (1- N))
         (FIB (- N 2)))))

(SETF (FDEFINITION 'FIB) ;既にあるFIBを置き換え
      (KL:MEMO-PROC #'FIB))

(FIB 100)
;⇒ 354224848179261915075

といったところ。