#:g1

mcsの紹介

Posted 2014-09-28 15:00:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の272日目です。

mcsとはなにか

 mcsは、Juergen Kopp氏が中心となって開発していたCLOSやTELOSの流れを汲むMOPを具備したオブジェクト指向システムです。
かつてドイツにあった、GMD(Gesellschaft für Mathematik und Datenverarbeitung mbH)で開発されていたようです。

パッケージ情報

配布サイトPackage: lang/lisp/oop/non_clos/mcs/
パッケージ名mcs
Quicklisp×

インストール方法

 上記の配布サイトからダウンロードしてきて適当にANSI CLで動くようにします。
もしくは、GitHub上にSBCLで動くようにしたものがありますので良かったらどうぞ。

Quicklispのlocal-projects以下に配置すれば

(ql:quickload :mcs)

できるかと思います。

試してみる

 mcsは以前も紹介したことがありましたが、主にMOP的なところを紹介してみていました。

 今回は、毎度お馴染のBankAccountです。

(defpackage :mcs.demo
  (:use :mcs))

(cl:in-package :mcs.demo)

(defabstract bank-account () ((dollars :initform 0 :accessor dollars :initarg dollars)))

(defclass normal-bank-account (bank-account) ())

(defmethod deposit ((a normal-bank-account) (n number)) (incf (dollars a) n))

(defmethod withdraw ((a normal-bank-account) (n number)) (setf (dollars a) (max 0 (- (dollars a) n))))

(defparameter *my-account* (make-instance 'normal-bank-account 'dollars 200))

(dollars *my-account*) ;=> 200

(deposit *my-account* 50) ;=> 250

(withdraw *my-account* 100) ;=> 150

(withdraw *my-account* 200) ;=> 0

(defclass stock-account (normal-bank-account) ((num-shares :initform 0 :accessor num-shares :initarg num-shares) (price-per-share :initform 30 :accessor price-per-share :initarg price-per-share)))

(defmethod dollars ((a stock-account)) (* (num-shares a) (price-per-share a)))

(defmethod (setf dollars) ((n number) (a stock-account)) (setf (num-shares a) (/ n (price-per-share a))) (dollars a))

(defparameter *my-stock* (make-instance 'stock-account 'num-shares 10))

(dollars *my-stock*) ;=> 300

(setf (dollars *my-stock*) 600) ;=> 600

(deposit *my-stock* 60) ;=> 660

(num-shares *my-stock*) ;=> 22

(withdraw *my-stock* 120) ;=> 540

(num-shares *my-stock*) ;=> 18

見ての通り、殆どCLOSと変わらないことが分かると思います。
上記のコードで目立った違いといえば、:initargにキーワードが使えないこと位でしょうか。
defabstractは全然必要ないのですが、mcsが標準で備えているのこともあり折角なので使ってみました。他にdefmixin等があります。

まとめ

 今回は、mcsを紹介してみました。
PCL(Portable Common Loops)よりは小さくまとまっているようなのでCLOSがないレガシーなシステムへ載せるものとしては結構良いかなと思ったりします。

pdfの紹介

Posted 2014-09-27 21:00:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の271日目です。

pdfとはなにか

 pdfは、PDFをChickenで扱うためのライブラリです。Marc Battyani氏作のCommon LispのPDFライブラリであるcl-pdfをBruce Butterfield氏がCLOS部分を構造体を使うようにしてSchemeに移植したものをMatt Gushee氏がChickenに移植したもののようです。

パッケージ情報

パッケージ名pdf
Chicken eggs:pdf - The Chicken Scheme wiki

インストール方法

$ sudo chicken-install pdf

すれば、

(use pdf)

(require-library pdf)

で使えます。

試してみる

 Bruce Butterfield氏のコメントによれば、当初CLOS部分の置き換えは、PLT Scheme(Racket)のクラスライブラリを使おうかと思ったそうですが、他の処理系でも使いたかったので移植性を考えて構造体を採用したそうです。

 こんな感じで書けば、

(define (Rotate-Demo)
  (with-document-to-file "Rotate-Demo.pdf"
   (let ((noto-sans (build-font "NotoSansJapanese")))
     (with-page
      (in-text-mode
       (set-font (font-name noto-sans) 36)
       (move-text 100 750)
       (draw-text "Rotate-Demo"))
      (translate 230 500)
      (do ((j 0 (+ j 1))
           (i 0.67 (* i 1.045)))
        ((= j 101))
        (in-text-mode
         (set-font (font-name noto-sans) i)
         (move-text (* i 3) 0)
         (draw-text "Rotate"))
        (rotate 18)))
     (with-page
      (in-text-mode
       (set-font (font-name noto-sans) 40)
       (move-text 230 500)
       (draw-text "That's All, Folks!"))))))

こんな感じのPDFが生成されます。

rotate-demo

まとめ

 今回は、pdfを紹介してみました。
他のSchemeの処理系にも移植とのことですが実際どうなんでしょう。ちらっと眺めた感じでは、確かにregexとfmtがあれば動きそうではあります。

regex-coachの紹介

Posted 2014-09-26 14:30:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の269日目です。

regex-coachとはなにか

 regex-coachは、Edi Weitz氏作の正規表現を対話的に確認/学習できるツールです。

パッケージ情報

パッケージ名regex-coach
Quicklisp×
プロジェクトサイトThe Regex Coach - interactive regular expressions

インストール方法

(ql:quickload :regex-coach)

試してみる

 Edi Weitz氏といえば、cl-ppcre等でCommon Lisp界では有名ですが、このregex-coachはcl-ppcreを利用し、LispWorksが提供する実行ファイル生成機能によって作られたアプリケーションです。

regex-coach

 ちょっと古いのが玉に瑕ですが、32bitのWindows版とLinux版があります。
プロジェクトサイトにダウンロードのリンクがありますので、ダウンロードして実行してみましょう。
Windows版はインストーラが走りますが、Linux版は実行ファイルがあるので、そのまま実行します。

まとめ

 今回は、regex-coachを紹介してみました。
ライブラリなのかというと微妙なところですが、まあ開発時に正規表現を確認できたりするので開発環境の一つということで。

RedditのLisp系の投稿をつぶやくTwitter bot作りました

Posted 2014-09-25 11:40:00 GMT

 前々から個人的に欲しいなあと思っていたのですが、誰も作らないので勝手に作りました。

 @reddit_lisp_jaの方は、r/lisp_jaの新着、@reddit_lispの方は、r/lisp、r/scheme、r/Racket、r/Shenlang、r/dylanlangのミックスです。
利用しているbot作成サービスの仕様で10分に一度の取得なので、連投になった場合、その時点の最新しか投稿されないというのが玉に瑕。
使い勝手が悪過ぎるなあと思った時は、自作しようかなと思います。

 利用状況は、あまりぱっとしませんが、まあ、こんなものかなあという感じです。

closure-htmlの紹介

Posted 2014-09-25 10:30:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の268日目です。

closure-htmlとはなにか

 closure-htmlは、Gilbert Baumann氏作のHTMLをパーズしてLHTML等に変換したり、LHTMLをHTMLにシリアライズしたりするライブラリです。

パッケージ情報

パッケージ名closure-html
Quicklisp
CLiKiCLiki: closure-html
Quickdocsclosure-html | Quickdocs
common-lisp.netClosure HTML
CL Test Grid: ビルド状況closure-html | CL Test Grid

インストール方法

(ql:quickload :closure-html)

試してみる

 どんな関数があるかは、Quickdocsで確認できます。

 closure-htmlは元々、Common Lisp製のブラウザのclosureの一部でしたが、closureは最近見掛けないので、一部だったことは既に忘れ去られているのではないでしょうか。
closureは5年位前まではビルドできた記憶があります。

 chtml:parseを利用して様々な形式に出力できますが、入力としては文字列とファイルが取れます。
変換先は なんとか-sinkや、なんとか-builderというのが用意されているので目的に応じて使い分けます。
closure-htmlに含まれているのは、

  • 文字列
  • LHTML
  • PT
  • ROD
  • 文字ストリーム
  • オクテットのベクタ

です。
他にもClosure系のライブラリで幾つか定義されているかなと思います(STP等)

(chtml:parse "<b>foo</b><foo>foo</foo>" (chtml:make-string-sink))
;=>  "<HTML><HEAD></HEAD><BODY><B>foo</B>foo</BODY></HTML>"

(chtml:parse "<b>foo</b><foo>foo</foo>" (chtml:make-pt-builder)) ;=> #<SGML:PT HTML ..>

(chtml:parse "<b>foo</b><foo>foo</foo>" (chtml:make-rod-sink)) ;=> "<HTML><HEAD></HEAD><BODY><B>foo</B>foo</BODY></HTML>"

(chtml:parse "<b>foo</b><foo>foo</foo>" (chtml:make-lhtml-builder)) ;=> (:HTML NIL (:HEAD NIL) (:BODY NIL (:B NIL "foo") "foo"))

(with-output-to-string (out) (chtml:parse "<b>foo</b><foo>foo</foo>" (chtml:make-character-stream-sink out))) ;=> "<HTML><HEAD></HEAD><BODY><B>foo</B>foo</BODY></HTML>"

(chtml:parse "<b>foo</b><foo>foo</foo>" (chtml:make-octet-vector-sink)) ;=> #(60 72 84 77 76 62 60 72 69 65 68 62 60 47 72 69 65 68 62 60 66 79 68 89 62 60 ; 66 62 102 111 111 60 47 66 62 102 111 111 60 47 66 79 68 89 62 60 47 72 84 77 ; 76 62)

RODと、PTってなんだろうという感じですが、RODは、Unicodeの文字列のことで、PTは、HAXというSAXのようなAPIで利用するデータ構造のようです。
PTを扱うツールも色々あるようです。

(sgml:ppt (chtml:parse "<b>foo</b><foo>foo</foo>" (chtml:make-pt-builder)))
;>>  
;>>  | HTML
;>>  `-----.
;>>        | HEAD
;>>        | BODY
;>>        `-----.
;>>              | B
;>>              +--.
;>>              |  | "foo" 
;>>              | "foo" 
;=>  ""

ちなみに、Runeというものも見掛けるのですが、Unicodeの文字のことで、RuneのベクタがRODということみたいです。
一応RuneとRodについてはドキュメントがあるようなので紹介しておきます。

 PTや、LHTMLからのHTMLへのシリアライズは、serialize-lhtmlや、serialize-ptを利用します。

(chtml:serialize-lhtml (chtml:parse "<b>foo</b><foo>foo</foo>" (chtml:make-lhtml-builder))
                       (chtml:make-string-sink))
;=>  "<HTML><HEAD></HEAD><BODY><B>foo</B>foo</BODY></HTML>"

まとめ

 今回は、closure-htmlを紹介してみました。
Closure関係のものには独自の用語が多いのですが、解説はあまりありません…。

alist-libの紹介

Posted 2014-09-24 11:30:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の267日目です。

alist-libとはなにか

 alist-libは、Peter Danenberg氏作のChickenのalistのライブラリです。

パッケージ情報

パッケージ名alist-lib
Chicken eggs:alist-lib - The Chicken Scheme wiki

インストール方法

$ sudo chicken-install alist-lib

すれば、

(use alist-lib)

で使えます。

試してみる

 srfi-1あたりにもalistを扱う関数はちょこちょこありますが、その辺とは被らないようなものが用意されているようです。
用意されているのは、こんな感じですが、名前から大体動作がわかるかなと思います。

  • alist-keys
  • alist-update!
  • alist-values
  • alist-ref
  • alist-fold
  • alist-map
  • alist-prepend!
  • alist-size
  • alist-set
  • alist-update!/default
  • alist-ref/default
(alist-map cons
           '((A . 65) (B . 66) (C . 67) (D . 68) (E . 69) (F . 70) (G . 71) (H . 72)))
;=> ((A . 65) (B . 66) (C . 67) (D . 68) (E . 69) (F . 70) (G . 71) (H . 72))

(alist-keys '((A . 65) (B . 66) (C . 67) (D . 68) (E . 69) (F . 70) (G . 71) (H . 72))) ;=> (A B C D E F G H)

(alist-values '((A . 65) (B . 66) (C . 67) (D . 68) (E . 69) (F . 70) (G . 71) (H . 72))) ;=> (65 66 67 68 69 70 71 72)

(let ((u (alist-copy '((A . 65) (B . 66) (C . 67) (D . 68) (E . 69) (F . 70) (G . 71) (H . 72))))) (alist-set! u 'A #f) u) ;=> ((A . #f) (B . 66) (C . 67) (D . 68) (E . 69) (F . 70) (G . 71) (H . 72))

(let ((u (alist-copy '((A . 65) (B . 66) (C . 67) (D . 68) (E . 69) (F . 70) (G . 71) (H . 72))))) (alist-update! u 'A (lambda (x) #f)) u) ;=> ((A . #f) (B . 66) (C . 67) (D . 68) (E . 69) (F . 70) (G . 71) (H . 72))

(alist-ref '((A . 65) (B . 66) (C . 67) (D . 68) (E . 69) (F . 70) (G . 71) (H . 72)) 'A) ;=> 65

assocしてcdrも面倒なのでalist-refは良いかもしれないですね。

まとめ

 今回は、alist-libを紹介してみました。
割合に奥が深いalist系関数。いつかalist関係の関数をまとめてみたいところです。

eggs: describeの紹介

Posted 2014-09-23 13:00:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の266日目です。

eggs: describeとはなにか

 eggs: describeは、Lisp方言ではお馴染のdescribeのChicken版です。

パッケージ情報

パッケージ名eggs: describe
Chicken eggs:describe - The Chicken Scheme wiki

インストール方法

$ sudo chicken-install describe

すれば、

(use describe)

で使えます。

試してみる

 Common Lispと同じように、(describe 調べたいオブジェクト)という感じです。

(describe describe)
;>> procedure with code pointer 7ffff3359596 of length 3
;>>  0: #<procedure (string-ref str i)>
;>>  1: #<procedure (length lst355)>
;>>  2: #<procedure (list-ref lst i)>

 Chickenは対話環境でコンマから開始されるコマンドが利用できますが、「,d」でdescribeが使えるようにもなります。

#;1> ,d describe
procedure with code pointer 7f414fb1d596 of length 3
 0: #<procedure (string-ref str i)>
 1: #<procedure (length lst355)>
 2: #<procedure (list-ref lst i)>

また、非常に長いリスト等を表示する場合には長さを限定したりもできます。

(parameterize ((describe-sequence-limit 5))
  (describe (iota 100)))
;>> list of length 100
;>>  0: 0
;>>  1: 1
;>>  2: 2
;>>  3: 3
;>>  4: 4
;>>  (95 elements not displayed)

,d コマンドの場合は、第二引数に長さを記述すれば同様の効果が得られます。

 また、set-describer!でタイプに表示関数を設定することにより表示をカスタマイズすることも可能です(詳しくはドキュメントを参照のこと)。

まとめ

 今回は、eggs: describeを紹介してみました。
~/.csircで(use describe)しておくと便利だと思います。
それはさておき、Chickenのdescribeは昔は標準機能だったような記述もポツポツ見掛けますが、分離しちゃったんでしょうか。

clawkの紹介

Posted 2014-09-22 11:00:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の265日目です。

clawkとはなにか

 clawkは、Kenneth Michael Parker氏作のCommon Lisp上でawkのような操作を実現するライブラリです。

パッケージ情報

パッケージ名clawk
Quicklisp
Quickdocsclawk | Quickdocs
CL Test Grid: ビルド状況clawk | CL Test Grid

インストール方法

(ql:quickload :clawk)

試してみる

 どんな関数があるかは、Quickdocsで確認できます。

 プログラミング言語AWKの初っ端にある例ですが、こんなファイル(名前 時給 労働時間)があったとして

Beth    4.00    0
Dan     3.75    0
Kathy   4.00    10
Mark    5.00    20
Mary    5.50    22
Suzie   4.25    18

これの人数、支払いの合計、支払いの平均を集計するにはawkだと、

{ pay = pay + $2 * $3 }
END { print NR, "employees"
      print "total pay is", pay
      print "average pay is", pay/NR
    }

みたいな感じですが、ファイルを開くのを含めて同じようなものを書くとCommon Lispでは、

(with-open-file (in "/tmp/emp.data")
  (let ((employees 0)
        (pay 0))
    (loop :for line := (read-line in nil) :while line
          :do (incf employees)
              (destructuring-bind (name w h) 
                                  (ppcre:split "\\s+" line)
                (declare (ignore name))
                (incf pay (* (read-from-string w)
                             (read-from-string h)))))
    (format t "~A employees~%" employees)
    (format t "total pay is ~A~%" pay)
    (format t "average pay is ~A~%" (/ pay employees))))
;>>  6 employees
;>>  total pay is 337.5
;>>  average pay is 56.25
;>>  
;=>  NIL

こんな感じです。
これを、clawkを使って書くと

(let ((pay 0) (employees 0))
  (for-file-fields ("/tmp/emp.data" (name w h))
    (declare (ignore name))
    (incf pay ($* w h))
    (incf employees))
  (format t "~A employees~%" employees)
  (format t "total pay is ~A~%" pay)
  (format t "average pay is ~A~%" (/ pay employees)))
;>>  6 employees
;>>  total pay is 337.5
;>>  average pay is 56.25
;>>  
;=>  NIL

とまあawkっぽく書けます。

CL上でawk風の記述を支援するユーティリティ

 便利に使えるユーティリティ関数が定義されていて、CLとawkが融合したような感じで書けます。

(for-file-fields ("/tmp/emp.data")
  ($print $3 $2 $1 " :" *nf*))
;>>  
;>>  0 4.00 Beth  : 3 
;>>  0 3.75 Dan  : 3 
;>>  10 4.00 Kathy  : 3 
;>>  20 5.00 Mark  : 3 
;>>  22 5.50 Mary  : 3 
;>>  18 4.25 Suzie  : 3 
;=>  NIL

 awkのプログラムだと、BEGIN、本体、ENDという構成がありますが、

(defawk foo ()
  (begin ($print "begin!"))
  (t ($print $3 $2 $1 " :" *nf*))
  (end ($print "end!")))

(with-input-from-string (s (format nil "foo~%bar~%baz")) (foo s)) ;>> ;>> begin! ;>> foo : 1 ;>> bar : 1 ;>> baz : 1 ;>> end! ;=> NIL

という感じに記述もできます。

 また、正規表現用にリーダーマクロが定義されていて、#/.../で記述することが可能です。

(*:defreadtable :awk
  (:merge :standard)
  (:dispatch-macro-char #\# #\` #'clawk::|#`-reader|)
  (:dispatch-macro-char #\# #\/ #'clawk::|#/-reader|)
  (:case :upcase))

(*:in-readtable :awk)

(for-file-fields ("/tmp/emp.data") (match-when (#/th/ ($print $3 $2 $1 " :" *nf*)))) ;>> ;>> 0 4.00 Beth : 3 ;>> 10 4.00 Kathy : 3 ;=> NIL

 さらに、#`...`でシェルコマンドを実行した結果を処理できるようですが、どうもコードを追加しないとLispWorksでしか動かないようです。

(for-stream-lines (#`ls /tmp/`)
  ($print *FNR* " " $0))

まとめ

 今回は、clawkを紹介してみました。
素直にawkを使えば良いんじゃないのかという話もありますが、ソースを眺めると、#+Generaという記述があるように元々はSymbolicsのLispマシン上でawk的なことをやりたかった、という記事をどっかで読んだ記憶があります。

interlisp: Advisingの紹介

Posted 2014-09-21 12:30:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の264日目です。

interlisp: Advisingとはなにか

 interlisp: Advisingは、interlispのアドバイス機構です。

パッケージ情報

参考マニュアルInterlisp Reference Manual(1974)

インストール方法

 interlisp-10や、Interlisp-Dでは標準の機能です。

試してみる

 アドバイス機構を紹介するのも何回目かという感じですが、今回は、元祖interlispのアドバイスの紹介です。
どうも本当の元祖は、interlispに先行するBBN-LISPみたいですが、1966-1972年のマニュアルでは記載を見付けられなかったので1974年のinterlispで確認しました。
試した環境は、pdp-10で稼動するinterlisp-10です。
REPLを開くとHiと挨拶をしてくれる処理系です(Xmasメッセージもあり)

 さて機能ですが、こんな感じの関数があったとすれば、

(DEFINEQ (matu (X)
           (PRIN1 '>>)
           (SPACES 1)
           (PRIN1 X)
           (TERPRI)))

(matu 8) ;>> >> 8

(ADVISE 'matu 'BEFORE '(PROGN
                        (PRIN1 '..before0:)
                        (TERPRI)))

(ADVISE 'matu 'BEFORE '(PROGN (PRIN1 '..before0:) (TERPRI)))

(advise 'matu '(PROGN (PRIN1 '..before1:) (TERPRI)))

(advise 'matu 'AFTER '(PROGN (PRIN1 '..after0:) (TERPRI)))

(ADVISE 'matu 'AFTER '(PROGN (PRIN1 '..after1:) (TERPRI)))

(ADVISE 'matu 'AROUND '(PROGN (PRIN1 '==>around0:) (TERPRI) * (PRIN1 '>==around0:) (TERPRI)))

(ADVISE 'matu 'AROUND '(PROGN (PRIN1 '==>around1:) (TERPRI) * (PRIN1 '>==around1:) (TERPRI)))

こんな感じにアドバイスをつけると、

(matu 8)
;>> ..before0:
;>> ..before1:
;>> ==>around1:
;>> ==>around0:
;>> >> 8
;>> >==around0:
;>> >==around1:
;>> ..after0:
;>> ..after1:
;=> NIL 

こんな感じになります。
上記では、アドバイスの順番を指定していないですが、指定しない場合は、後に追加になります。
これは、(first top)/(last bottom end)で前後を指定可能になっています。

(DEFINEQ (zzz () (PRINT 'zzz)))

(ADVISE 'zzz 'BEFORE 'TOP '(PRINT 'hello1)) (ADVISE 'zzz 'BEFORE 'TOP '(PRINT 'hello2))

(zzz) ;>> hello2 ;>> hello1 ;>> zzz ;=> zzz

 面白いのが、関数内の関数にもアドバイスがかけられることで、

(DEFINEQ
  (foo () (PRIN1 'foo) (TERPRI))
  (bar () (PRIN1 'bar)(TERPRI))
  (baz () (PRIN1 'baz)(TERPRI))
  (makanito () (foo) (bar) (baz)))

 こんな感じの定義がある場合、

(ADVISE '((foo baz) IN makanito)
        'AROUND '(PROGN
                  (PRIN1 '>>)
                  (TERPRI)
                  *
                  (PRIN1 '<<)
                  (TERPRI)))

という定義で

(makanito)
;>> >>
;>> foo
;>> <<
;>> bar
;>> >>
;>> baz
;>> <<
;=> NIL

makanito内のfooとbazにアドバイスをかけることができます。
アドバイスの削除は、unadviseで、削除します。

(unadvise 'zzz)

まとめ

 今回は、interlisp: Advisingを紹介してみました。
上記のコード例を見てinterlispは標準状態の入力時でCommon Lispのようにcaseの変換をしないのに気付いたでしょうか。
大文字小文字はそのまま反映されるため標準関数は大文字で入力する必要があるということで、Common Lispでいうリードテーブルを:preserveモードにした時の挙動と同じということなんですが、一々大文字で入力しなくてもDWIM機能で対話的に修正してくれます(といっても面倒臭いですが)。
ただし、BEFORE、AFTER等の識別子は、DWIM機能が働いてくれなかったりするので気をつける必要があるみたいです。

Clozure CL: Static Variablesの紹介

Posted 2014-09-19 12:30:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の262日目です。

Clozure CL: Static Variablesとはなにか

 Clozure CL: Static Variablesは、Clozure CLの機能でスレッドの違いによらないグローバルな変数を実現するものです。

パッケージ情報

パッケージ名Clozure CL: Static Variables
参考サイトClozure CL: 4.8. Static Variables

インストール方法

 Clozure CL標準で提供されていて、CCLパッケージ内で定義されています。シンボルはエクスポートされていますが、cl-userには標準状態でインポートされています。

試してみる

 Clozure CLでのStatic Variableの定義は、スレッド間でも共通のグローバル変数で、束縛構文による束縛は禁止で代入しかできない変数です。
他の処理系だとLispマシンの時代から、大体defglobalとか、なんとか-globallyという名前で提供されています。

 提供されている機能は、マニュアルによるとdefstaticのみですが、兄弟にdefstaticvarというものもあるようです。
これらは、defparameterとdefvarの関係で、destaticvarの方がdefvarにあたります。

(defstatic **foo** 42)

(let ((**foo** 8)) **foo**) ;!> **FOO** is declared static and can not be bound

(setq **foo** 8) ;=> 8

(defvar **bar** 42)

(defstaticvar **bar** 84)

**bar** ;=> 42

 defstaticvarではdefvarのでの宣言のように未束縛のままにしておくというのができないのが謎ですが、何か理由があるのでしょうか。
ちなみに、処理系の実装を眺める限りでは、未束縛のStatic Variableは作ろうと思えば作れるようです。

(defvar **baz**)

(ccl::%symbol-bits '**baz** 20) ;20は、Static Variableのフラグ

(boundp '**baz**) ;=> NIL

(let ((**baz** 42)) **baz**) ;!> **BAZ** is declared static and can not be bound

まとめ

 今回は、Clozure CL: Static Variablesを紹介してみました。
Lispマシンにあった機能が脈々と受け継がれていたり、浮上してきたりするのは面白いところですね。

Older entries (1843 remaining)