#:g1

cl-notebookの紹介

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

(LISP Library 365参加エントリ)

 LISP Library 365 の180日目です。

cl-notebookとはなにか

 cl-notebookは、Leo Zovic(Inaimathi)氏によるIPython Notebookに影響を受けたブラウザベースの対話的なCommon Lisp環境です。

パッケージ情報

インストール方法

 現在Quicklispでは配布されていないので、githubからダウンロードして、Quicklispでロードできるようにlocal-projects以下などに設置します

設置できたら、

(ql:quickload :cl-notebook)

でロードできます。

 また、サーバの実行ファイルを作るのに buildapp が必要なようです。buildappは

(ql:quickload :buildapp)

でインストールできます。
(buildapp:build-buildapp)して、buildappを生成し、パスの通ったところに置いておきましょう。

 なお、サーバの実行ファイルは、バイナリでも配布されているようです。

試してみる

 まず、作者自身によるcl-notebookの紹介ビデオがありますので、これを観るのが一番手っ取り早いかと思います。

 ビデオを観て試してみたいと思ったらセットアップしてみましょう。以下では、バイナリではなく、ソースからビルドする方法を紹介します(SBCLの場合)。
上記githubのページから cl-notebookのソースを取得し、cl-notebookのディレクトリに移動します。

$ build.sh

とすると、cl-notebookという実行ファイルができますので、

$ ./cl-notebook

で起動します。デフォルトでは、4242番ポートで起動しますが、-pオプションでポートは変更できるようです。
起動したら、ブラウザでlocalhost:4242/を開いてみましょう。

 なおSLIMEから起動する場合は、

(cl-notebook::main-dev)

で起動するのが良いようです。

cl-notebook

+New Bookで新しいファイル +New Cellで新しい式を作成できます。
式を入力したら、Ctrl+Enterで評価されます。
なお、どうも現時点では日本語は文字化けするようです。

まとめ

 今回は、cl-notebookを紹介してみました。
最近は何かとブラウザベースなものが多いですが、Common Lispでもこういう動きが出てきたのは素晴らしいですね。

cl-ntriplesの紹介

Posted 2014-06-26 18:15:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の178日目です。

cl-ntriplesとはなにか

 cl-ntriplesは、Victor Anyakin氏作のCommon Lisp製のN-Triplesのパーザです。

パッケージ情報

パッケージ名cl-ntriples
Quicklisp
CLiKihttp://cliki.net/cl-ntriples
Quickdocshttp://quickdocs.org/cl-ntriples
CL Test Grid: ビルド状況cl-ntriples | CL Test Grid

インストール方法

(ql:quickload :cl-ntriples)

試してみる

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

 RDFには表記形式がXMLやN3等様々ありますが、cl-ntriplesは名前の通り、N-Triplesを扱います。

<http://dbpedia.org/resource/Yokohama>	<http://dbpedia.org/property/julHumidity>	"80"^^<http://www.w3.org/2001/XMLSchema#integer> .

こんな行があったとすると、

("http://dbpedia.org/resource/Yokohama" 
 "http://dbpedia.org/property/julHumidity"
 (:LITERAL-STRING "80" :URIREF "http://www.w3.org/2001/XMLSchema#integer"))

こんな感じの3つ組のリストとして読み込まれるようで、型付リテラルは、さらに注釈がリストとして表現されるようです。

 さらに、おまけで、nt:predicate?という簡単なクエリ用の関数が付いてくるので、簡単な検索ができます。

(defvar *Yokohama* (nt:parse-nt (drakma:http-request "http://dbpedia.org/data/Yokohama.ntriples")))

;;; 横浜の緯度 (nt:predicate? *Yokohama* "http://www.w3.org/2003/01/geo/wgs84_pos#lat") ;=> (("http://dbpedia.org/resource/Yokohama" ; "http://www.w3.org/2003/01/geo/wgs84_pos#lat" ; (:LITERAL-STRING "35.45" :URIREF "http://www.w3.org/2001/XMLSchema#float")) ; ("http://dbpedia.org/resource/Yokohama" ; "http://www.w3.org/2003/01/geo/wgs84_pos#lat" ; (:LITERAL-STRING "35.4442" :URIREF "http://www.w3.org/2001/XMLSchema#float")))

;;; 横浜の経度 (nt:predicate? *Yokohama* "http://www.w3.org/2003/01/geo/wgs84_pos#long") ;=> (("http://dbpedia.org/resource/Yokohama" ; "http://www.w3.org/2003/01/geo/wgs84_pos#long" ; (:LITERAL-STRING "139.638" :URIREF "http://www.w3.org/2001/XMLSchema#float")) ; ("http://dbpedia.org/resource/Yokohama" ; "http://www.w3.org/2003/01/geo/wgs84_pos#long" ; (:LITERAL-STRING "139.633" :URIREF "http://www.w3.org/2001/XMLSchema#float")))

;;; 横浜は何の一部か (nt:predicate? *Yokohama* "http://dbpedia.org/ontology/isPartOf") ;=> (("http://dbpedia.org/resource/Yokohama" "http://dbpedia.org/ontology/isPartOf" ; (:OBJECT-URIREF "http://dbpedia.org/resource/Kanagawa_Prefecture")) ; ("http://dbpedia.org/resource/Yokohama" "http://dbpedia.org/ontology/isPartOf" ; (:OBJECT-URIREF "http://dbpedia.org/resource/Kant%C5%8D_region")))

まとめ

 今回は、cl-ntriplesを紹介してみました。
やはり、N-Triplesより、リスト表現の方が扱いやすいですね。

lisp-criticの紹介

Posted 2014-06-25 15:30:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の177日目です。

lisp-criticとはなにか

 lisp-criticは、Christopher K. Riesbeck氏作のCommon Lispのコードを批評してくれるユーティリティです。
ノースウェスタン大学のコンピュータ科学のコース EECS 325 AI Programming での学習用のツールとして開発されたようです。

パッケージ情報

パッケージ名lisp-critic
Quicklisp×
プロジェクトサイトExercise Checking Tools

インストール方法

 Quicklispに収録されてるかなと思って検索してみたところ、どうもまだ収録されていないようなので、上記プロジェクトサイトから必要な物をダウンロードしてセットアップします。
必要なものをまとめてgithubに置いてみているので良かったらどうぞ

Quicklispのlocal-projects等に置けば、Quicklispでロードできます。

(ql:quickload :lisp-critic)

試してみる

 3年前にも紹介してみましたが、その時は、SLIMEの*slime-repl*バッファに出力するようにしてみました。
以来、この3年間使い続けてみましたが、全くといって良い程無視してしまっています。
もうちょっと目立つなら、少しは読むようになるかもということで、デスクトップ通知でもさせてみることにします。

デスクトップ通知 + SLIME + lisp-critic

 SLIME(Emacs)側は、

(defadvice slime-compile-defun (before critique-advice activate)
  (slime-eval `(swank::lisp-critic ,(slime-defun-at-point) :timeout 5000)))

のように slime-compile-defun に advice を付けて、Common Lisp側では、

(defun ?::notify-send (title mesg &key (timeout 10)
                                 (icon "lisplogo_alien_256.png")
                                 (urgency :normal))
  (*:run-program "notify-send"
                 (list "-u" (string-downcase urgency)
                       "-t" (princ-to-string timeout)
                       "-i" icon
                       "--"
                       title
                       mesg)
                 :search T))

(defun swank::lisp-critic (string &key (timeout 1000)) (let ((mesgs (with-output-to-string (*standard-output*) (lisp-critic:critique-definition (read-from-string string))))) (dolist (m (remove "" (*:split "\\s*-{10,}\\s*" mesgs) :test #'string=)) (?:notify-send "Lisp Critic" m :timeout timeout))) nil)

のような感じでデスクトップ通知にメッセージを投げます。
REPLに出力する為に整形したものを更に切り出している所が無駄ですが、これ以上は、lisp-criticの中身をいじることになりそうなので、とりあえず今回はこれで良しとします。

 動作イメージとしては、こんなコードをコンパイルすると…

(defun foo ()
  (defun bar ()
    (setq a 'b)))
lisp-critic

みたいに批評されます。
結構表示がウザいですが、これなら読むようになるかも。

批評をカスタマイズする

 批評は、lisp-rules.lisp の中で定義されていますが、define-lisp-patternというもので定義します。
こんな感じに

(define-lisp-pattern copy-array
    (copy-array (?))
  "There is no COPY-ARRAY in Standard Common Lisp. You have to create ~
   an empty array and fill it as needed.")

拾いたいパタンと、メッセージを定義してやればOKです。

関連

まとめ

 今回は、lisp-criticを紹介してみました。
Common Lisp製のツールをカスタマイズして使うこと自体Common Lispの良い勉強になると思うので、こういったツールを整備してみるのもなかなか良いのではないでしょうか。

paren-utilの紹介

Posted 2014-06-24 15:00:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の176日目です。

paren-utilとはなにか

 paren-utilは、Red Daly氏作のParenScriptを便利に使う為のライブラリですが、Common Lisp側というより主にParenScript側のライブラリです。

パッケージ情報

パッケージ名paren-util
Quicklisp
Quickdocshttp://quickdocs.org/paren-util
CL Test Grid: ビルド状況paren-util | CL Test Grid

インストール方法

(ql:quickload :paren-util)

試してみる

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

 Quickdocsで確認できるのは主にLisp側になりますが、ソースを眺めてみるとどうもParenScriptで書いたライブラリ部分がメインのようです。util.parenがユーティリティの本体で、Common Lispでお馴染のevery、find、subseq等の関数も定義されていたりはしますが、まあ、そっちはオマケという感じかもしれません。
一応並べてみると、

  • equal
  • eql
  • identity
  • length
  • subseq
  • find
  • every
  • some
  • remove
  • remove-duplicates
  • arrayp
  • stringp
  • nreverse

が定義されていたりはします。
他、anaphoraを移植しようとした形跡がありますが、まだ動くようにはなっていないようです。

 使い方ですが、こんな感じのファイル one-plus-two.parenがあったとすれば、

;; -*- mode: lisp -*-

(in-package :paren-util)

(defun pr (s) ((ps:@ document write) s))

(defun one-plus-one () (pr "<b>1+2</b>の答えは") (pr (+ 1 2)) (pr "です!") nil)

(defun iota (n &optional (start 0) (step 1)) (let ((ans '())) (dotimes (i n ans) (push-on-end start ans) (incf start step))))

(defun print-list (list) (pr "<ul>") (dolist (e list) (pr "<li>") (pr (escape-html ">>")) (pr e) (pr (escape-html "<<")) (pr "</li>")) (pr "</ul>"))

これとライブラリを

(paren-files:compile-script-file-to-js-file
 (asdf:system-relative-pathname :paren-util "src/paren/util.paren")
 :destination-file "util.js")

(paren-files:compile-script-file-to-js-file "one-plus-two.paren")

こんな感じでコンパイルして、htmlかなにかから読み込みという感じでしょうか。

まとめ

 今回は、paren-utilを紹介してみました。
JavaScriptをCommon Lispっぽく書けるだけでもやっぱり嬉しいですね。

paren-filesの紹介

Posted 2014-06-23 15:00:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の175日目です。

paren-filesとはなにか

 paren-filesは、Red Daly氏作のparenscriptをコンパイルしたりASDFと組み合わせて利用するのに便利なユーティリティです。

パッケージ情報

パッケージ名paren-files
Quicklisp
Quickdocshttp://quickdocs.org/paren-files
CL Test Grid: ビルド状況paren-files | CL Test Grid

インストール方法

(ql:quickload :paren-files)

試してみる

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

 下記のようなone-plus-one.parenというParenScriptのファイルがあったとすれば、

(defun pr (s)
  ((ps:@ document write) s))

(defun one-plus-one () (pr "<b>1+1</b>の答えは") (pr (+ 1 1)) (pr "です!") nil)

(paren-files:compile-script-file-to-js-file "one-plus-one.paren")
;=>  "function pr(s) {
;        return document.write(s);
;    };
;    function onePlusOne() {
;        pr('<b>1+1</b>\\u306E\\u7B54\\u3048\\u306F');
;        pr(1 + 1);
;        pr('\\u3067\\u3059\\uFF01');
;        return null;
;    };
;    "

(paren-files:compile-script-file "one-plus-one.paren") ;>> function pr(s) { ;>> return document.write(s); ;>> }; ;>> function onePlusOne() { ;>> pr('<b>1+1</b>\u306E\u7B54\u3048\u306F'); ;>> pr(1 + 1); ;>> pr('\u3067\u3059\uFF01'); ;>> return null; ;>> }; ;>> ;=> "function pr(s) { ; return document.write(s); ; }; ; function onePlusOne() { ; pr('<b>1+1</b>\\u306E\\u7B54\\u3048\\u306F'); ; pr(1 + 1); ; pr('\\u3067\\u3059\\uFF01'); ; return null; ; }; ; "

のように使えます。
他、paren-files:compile-script-file-to-string 等があります。

ADSFとの連携

 parenscriptをjsにコンパイルするためのcompile-opが定義してあるので、システムをロード時などにparenscriptをコンパイルさせることも可能です。

(cl:in-package :asdf)

(defsystem :paren-files-demo :serial t :defsystem-depends-on (:paren-files) :depends-on (:fiveam) :components ((:file "package") (:file "paren-files-demo") (:parenscript-file "one-plus-one") (:file "test")))

(defmethod perform ((op compile-op) (paren-file parenscript-file)) (symbol-call :paren-files :compile-script-file-to-js-file (component-pathname paren-file)))

 こんな感じに

:defsystem-depends-on (:paren-files)

を追加すれば、:componentに:parenscript-fileが利用できるようになり、compile-op実行時にparen-files-demo.parenと同じディレクトリへparen-files-demo.jsが生成されます。

まとめ

 今回は、paren-filesを紹介してみました。
JavaScriptは手書きしないでParenScriptで通す、という人には便利かもしれないですね。

date-literalsの紹介

Posted 2014-06-22 15:00:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の174日目です。

date-literalsとはなにか

 date-literalsは、Arto Bendiken氏作のChickenで日付オブジェクトのリテラル表記を可能にするライブラリです。

パッケージ情報

パッケージ名date-literals
Chicken eggs:Date-literals - The Chicken Scheme wiki

インストール方法

$ sudo chicken-install date-literals

すれば、

(use date-literals)

(require-extension date-literals)

で使えるようになる筈なんですが、形式が古いのか何なのか自分の手元では上手く行きませんでした。
ライブラリのファイルで date-literals.so というのを作法に従って date-literals.import.so にしたら読み込むことは読み込むのですが…

試してみる

 srfi-19のdateのリテラル表記を提供するもので、#@から始まる表記がdateオブジェクトになります。

(date? #@2014-06-22T13:43:59+0900)
;=> #t

(make-date 0 0 0 0 1 1 2000 0) ;=> #@2000-01-01T00:00:00Z

(date->time-utc #@2000-01-01T00:00:00Z) ;=> #,(time utc 0 946684800)

Chickenの場合、標準で、SRFI-10が有効になっているようなので、そんなに必要もないでしょうか。
ただSRFI-10の形式だと

#,(date 644000000 53 53 14 22 6 2014 32400 JST #f #f #f #f)

のように長いのでdate-literalsの方が可読性は高いかなとは思います。

 ちなみにChickenでのリーダーマクロですが、#から始まるものは、

(set-sharp-read-syntax! #\@ read-date-literal)

のように簡単に定義可能なようです。

まとめ

 一発ネタのライブラリでしたが、Chickenでもリーダーマクロを定義して使ったりするんですね。

eosの紹介

Posted 2014-06-21 15:30:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の173日目です。

eosとはなにか

 eosは、Adlai Chandrasekhar氏開発のテストのフレームワークです。

パッケージ情報

パッケージ名eos
Quicklisp
CLiKihttp://cliki.net/eos
Quickdocshttp://quickdocs.org/eos
CL Test Grid: ビルド状況eos | CL Test Grid

インストール方法

(ql:quickload :eos)

試してみる

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

 ロードするといきなり

************************ ** Eos is deprecated! ** ** See README.mkdn ** ************************

と表示されますが、指示の通りREADME.mkdnを読むと、Edward Marco Baringer氏のFiveAMの開発停止宣言にともなってフォークしたeosですが、FiveAMが開発続行になったのでいらなくなっちゃった的なことが書いてあります。
なるほど、道理で似ている訳ですが、ちょっと悲しい。

 使い方は、こんな風に、FiveAMとまったく同じ感じで使えます。


(defpackage :eos.example
  (:use :cl :eos)) 

(in-package :eos.example)

(def-suite eos.example)

(in-suite eos.example)

(defun list-42 () (*:iota 42))

(defun list-100 () (*:iota 100))

(test length=42 (is (= 42 (length (list-42)))))

(test length=100 (is (= 100 (length (list-100)))) (is (= 100 (length (list-42)))))

(define-condition latumofis (error) ())

(test signal-latumofis (signals latumofis (error 'latumofis)))

(run! 'eos.example) ;>> ..f. ;>> Did 4 checks. ;>> Pass: 3 (75%) ;>> Skip: 0 ( 0%) ;>> Fail: 1 (25%) ;>> ;>> Failure Details: ;>> -------------------------------- ;>> LENGTH=100 []: ;>> (LENGTH (LIST-42)) evaluated to 42, which is not = to 100.. ;>> --------------------------------

おまけ

 折角なのでeosがdeprecatedなアナウンスをどうやって出しているのかを眺めてみましょう。
メッセージを出しているところを探してみると、

(defmethod asdf:operate :before ((op asdf:load-op)
                                 (system (eql (asdf:find-system :Eos)))
                                 &rest proclamations)
  (declare (ignore proclamations))
  (format t "~2&************************~@
                ** Eos is deprecated! **~@
                **   See README.mkdn  **~@
                ************************~%"))

のようにasdf:operateのasdf:load-opの:beforeで出すようになっていました。
~@はあまり見掛けませんが、~@という指示子ではなく、~<改行>という指示子が@のオプションを取っているものです。これは改行以外の空白は無視する、というもの。このコードはインデント付きで書かれていますが、囲み文として整形するためのインデントを無視するということになります。
最初からインデント無しで書けば良いじゃないかという話でもありますが、コードを綺麗に整形したかったのではないでしょうか。なかなか芸が細かい。

まとめ

 今回は、eosを紹介してみました。
確かFiveAMの停滞から開発停止、開発者の引き継ぎまでは結構な2、3年あったような気もしますが、停滞が長引くとこういうことも起きたりするんですね。

incf-clの紹介

Posted 2014-06-21 11:00:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の172日目です。

incf-clとはなにか

 incf-clは、Juan M. Bello Rivas氏作のCommon Lispのユーティリティ集です。

パッケージ情報

パッケージ名incf-cl
Quicklisp
CLiKihttp://cliki.net/incf-cl
Quickdocshttp://quickdocs.org/incf-cl
CL Test Grid: ビルド状況incf-cl | CL Test Grid

インストール方法

(ql:quickload :incf-cl)

試してみる

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

 incf関係を拡張するユーティリティなのかと思ってインストールしてみましたが、incfの意図は、C系文化で良くあるCL++ということみたいです。

 ユーティリティの内容ですが、Haskell等で良く使われているユーティリティを模しているようです。

内包表記

 LOOPに展開されるマクロです。LOOPは元々内包表記っぽく書けますが、それを推し進めた感じです。

(lc x (<- x '(1 2 3 4)))
;=>  (1 2 3 4)

(lc (list x y) (<- x '(1 2 3 4)) (<- y '(1 2 3 4)))
;=>  ((1 1) (1 2) (1 3) (1 4) (2 1) (2 2) (2 3) (2 4) (3 1) (3 2) (3 3) (3 4) (4 1)
;     (4 2) (4 3) (4 4))

doctest

 最近の言語では良くあるドキュメントストリングにテストを書くというもの。

パッケージ名> 式 結果

と書くと、doctest関数でテスト可能です。パッケージ丸ごとという指定も可能

(defpackage katino 
  (:use :cl :incf-cl))

(cl:in-package :katino)

(defun fib (n) " KATINO> (fib 0) 0 KATINO> (fib 1) 1 KATINO> (fib 2) 1 KATINO> (fib 10) 55" (if (< n 2) n (+ (fib (1- n)) (fib (- n 2)))))

(doctest 'katino::fib) ;>> .... ;=> T

HaskellのPrelude

 HaskellのPreludeに含まれているものを模した関数もあります。

  • break*
  • cycle
  • ncycle
  • drop
  • drop-while
  • flip
  • group
  • insert
  • intersperse
  • nintersperse
  • partition
  • replicate
  • scan*
  • span
  • split-at
  • take
  • take-while
  • unzip

その他

 その他、関数合成の$、ネストしたリストを扱うnest関数、ハッシュテーブルのユーティリティ、unfold、文字列連結等があります。

(nest-list #'list 1 :max 10)
;=>  (1 (1) ((1)) (((1))) ((((1)))) (((((1))))) ((((((1)))))) (((((((1)))))))
;     ((((((((1)))))))) (((((((((1))))))))) ((((((((((1)))))))))))

(nest-list #'list '(1 1) :max 8) ;=> (1 1 (1 1) (1 (1 1)) ((1 1) (1 (1 1))) ((1 (1 1)) ((1 1) (1 (1 1)))) ; (((1 1) (1 (1 1))) ((1 (1 1)) ((1 1) (1 (1 1))))) ; (((1 (1 1)) ((1 1) (1 (1 1)))) ; (((1 1) (1 (1 1))) ((1 (1 1)) ((1 1) (1 (1 1)))))) ; ((((1 1) (1 (1 1))) ((1 (1 1)) ((1 1) (1 (1 1))))) ; (((1 (1 1)) ((1 1) (1 (1 1)))) ; (((1 1) (1 (1 1))) ((1 (1 1)) ((1 1) (1 (1 1))))))) ; ((((1 (1 1)) ((1 1) (1 (1 1)))) ; (((1 1) (1 (1 1))) ((1 (1 1)) ((1 1) (1 (1 1)))))) ; ((((1 1) (1 (1 1))) ((1 (1 1)) ((1 1) (1 (1 1))))) ; (((1 (1 1)) ((1 1) (1 (1 1)))) ; (((1 1) (1 (1 1))) ((1 (1 1)) ((1 1) (1 (1 1)))))))))

(nest-list #'+ '(1 1) :max 8) ;=> (1 1 2 3 5 8 13 21 34 55)

(nest #'+ '(1 1) :max 8) ;=> 55 (mapcar ($ #'list #'+) '(1 2 3 4) '(5 6 7 8)) ;=> ((6) (8) (10) (12))

(dohash (key value (*:alist-hash-table '((a . 1) (b . 2) (c . 3)))) (format t "~A => ~D~%" key value)) ;>> A => 1 ;>> B => 2 ;>> C => 3 ;>> ;=> NIL (string-join (list "foo" "bar") "") ;=> "foobar"

まとめ

 今回は、incf-clを紹介してみました。
incf-clは結構、利用頻度が高そうなものが揃っているので、なかなか使えそうですね。

gauche.collectionの紹介

Posted 2014-06-20 12:30:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の171日目です。

gauche.collectionとはなにか

 gauche.collectionは、Gaucheのコレクションタイプ全般に共通で便利に利用できる枠組みを提供するモジュールです。

パッケージ情報

パッケージ名gauche.collection
マニュアルGauche ユーザリファレンス: 9.4 gauche.collection - コレクションフレームワーク

インストール方法

 Gaucheの標準で添付されているので、

(use gauche.collection)

のみで利用可能です。

試してみる

 マニュアルに一通りの説明があり、リスト操作の関数に馴れている人ならば、すぐに使い方も分かるような構成になっています。

 マップや畳み込みとして、

  • fold
  • fold2
  • fold3
  • map
  • map-to
  • map-accum
  • for-each

 要素を探したり、除外したり、まとめたりするものとして

  • find
  • find-min
  • find-max
  • find-min&max
  • filter
  • filter-to
  • remove
  • remove-to
  • partition
  • partition-to
  • group-collection

 変換するものとして

  • coerce-to

 その他、

  • size-of
  • lazy-size-of

があります。

 これらについて、標準で

  • <list>
  • <vector>
  • <string>
  • <hash-table>
  • 単一型のベクタ

が利用可能になっていますが、

 ユーザーが枠組みを拡張するために

  • call-with-iterator
  • call-with-builder
  • with-iterator
  • with-builder
  • call-with-iterators

が用意されていて、<collection>を継承してcall-with-iteratorを実装すれば拡張可能になっています。
例えば、双方向リストを作法に則って作成すれば、gauche.collectionで提供されている関数がそのまま利用できて便利という具合。

 個人的に便利だなと思うのは、<hash-table>の統合のされ具合で、

(~ (map-to <hash-table> values '((e . 4) (c . 2) (g . 6) (f . 5) (b . 1) (a . 0) (d . 3)))
   'e)
;=> 4

(~ (map-to <hash-table> cons '(e c g f b a d) '(4 2 6 5 1 0 3)) 'e) ;=> 4

(let ((tab (map-to <hash-table> cons '(a b c d e f g) (iota 100)))) (list (~ tab 'a) (~ tab 'c) (~ tab 'e))) ;=> (0 2 4)

(let ((tab (map-to <hash-table> cons '(a b c d e f g) (iota 100)))) (coerce-to <list> tab)) ;=> ((e . 4) (c . 2) (g . 6) (f . 5) (b . 1) (a . 0) (d . 3))

こんな感じで既存のリスト操作のイディオムとの統一感もあって使いやすくなっています。
また、

(group-collection '((a 1) (c 2) (a 3) (d 2) (z 3) (a 1) (c 2) (z 1) (a 2) (c 3) (d 2) (e 3))
                  :key car)
;=> (((a 1) (a 3) (a 1) (a 2)) ((c 2) (c 2) (c 3)) ((d 2) (d 2)) ((z 3) (z 1)) ((e 3)))

も、ちょっとした時に使いたいこと多い処理なので便利だなと思います。

まとめ

 今回は、gauche.collectionを紹介してみました。
gauche.collectionは使い勝手が良いので、Gaucheに限らず他の方言や処理系にもあったら良いなあと思ったりです。

medley/miscの紹介

Posted 2014-06-18 16:00:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の170日目です。

medley/miscとはなにか

 medley/miscは、CMUのAIレポジトリに置かれているXerox Medleyで動くInterlisp-Dや、Xerox Common Lisp用のプログラム集です。

パッケージ情報

パッケージ名medley/misc
配布サイトPackage: lang/lisp/code/impdep/medley/

インストール方法

 特にパッケージシステム的なものもないのでファイルをloadします。

試してみる

 配布されているmisc.tgzの中身のうちソースコードは大体下記の通りです。

  • PRINTSERVER
  • canvasconverter
  • doc-objects
  • heffron-postscript
  • makefiletextpatch
  • nsasciipatch
  • pp-code-file
  • rolo
  • starbg
  • tmax-ngraph
  • activeregions
  • cd
  • documentationpatch
  • fontsampler
  • hgraph
  • makegraph
  • nscopyfile
  • preemptive
  • rpc
  • step-command-menu
  • tmax-ngroup
  • add-sedit-commands
  • chat
  • donz
  • ftpserverpatch
  • hpgl
  • manager
  • nsdisplaysizes
  • pressfromns
  • rpccommon
  • storage
  • tmax-number
  • address
  • cl-ttyedit
  • granite
  • idlehax
  • nsprotection
  • prettyfileindex
  • rpclowlevel
  • systats
  • tmax-xref
  • airegions
  • clock
  • dovekeyboards
  • graph-pcl
  • inspectcode-tedit
  • mandelbrot
  • nstalk
  • rpcos
  • talk
  • todo
  • airegions-demo
  • closeallpatch
  • dpupftppatch
  • graphcalls
  • invisiblewindow
  • mathtons
  • nstalkgap
  • printermenu
  • rpcportmapper
  • talkgap
  • trajectory-follower
  • analyzer
  • commands
  • dspgraphtranspatch
  • grep
  • iptalk
  • microtek
  • pac-man-idle
  • profiler
  • rpcrpc
  • trickle
  • ansikeypad
  • commentstrings
  • dspscale
  • grid-icons
  • keyobj
  • microtekprint
  • pacman
  • promptreminders
  • rpcstruct
  • tcptime
  • ttytalk
  • ansikeypaddata
  • common-makefile
  • editbg
  • kinetic
  • missile
  • pagehold
  • proofreader
  • rpcxdr
  • turbo-windows
  • autobind
  • commwindow
  • editkeys
  • kotologo
  • mlabel-demo.mlabel
  • phone-directory
  • ps-send
  • screenpaper
  • tedit-emacs-translator
  • twodgraphics
  • background
  • compilebang
  • environmentpatch
  • h-env
  • layout-sedit
  • mlabel
  • pict
  • ps-tty
  • sedit-compile
  • teditkey
  • unboxedops
  • background-parc.press
  • courierdefs
  • equationforms
  • h-load
  • piece-menus
  • qedit
  • sedit-menu-always
  • tedittalk
  • uuencode
  • background-rhine.press
  • courierevalserve
  • equations
  • life
  • monitor
  • planets
  • qix
  • setdefaultprinter
  • therm
  • vstats
  • courierimagestream
  • etherboot
  • lispxconvert
  • multich
  • play
  • readais
  • showtime
  • tiled-sedit
  • wdwhacks
  • background-twodollar.press
  • courierserve
  • etherinfo
  • h-patches
  • multimenu
  • plot
  • readbrush
  • singlefileindex
  • tinytidy
  • who-line
  • backgroundimages
  • dateformat-editor
  • h-source
  • loadfiletypepatch
  • multiple-hardcopy
  • plotexamples
  • readdatatype
  • sketchtalk
  • tmax
  • whocalls
  • bitmap
  • daybreakkeyboards
  • fbsettypepatch
  • hanoi
  • loadmenuitems
  • multiw
  • plotobjects
  • region
  • solid-movew
  • tmax-date
  • xcl-bridge
  • boundary
  • defaultsubitemfn
  • fillregion
  • hashbuffer
  • lookupinfiles
  • neaticons
  • plotobjects1
  • register-machine
  • solitaire
  • tmax-endnote
  • bsearch
  • finger
  • hashdatum
  • macpaint
  • notepad
  • port-clfile
  • remotepsw
  • spellingarray
  • tmax-index
  • calendar
  • dirgrapher
  • fm-creator
  • headline
  • notepad-corestyles
  • postscript
  • resize-filebrowser
  • split-file

 拡張子があったりなかったりするのですが、ファイルの先頭に、

(DEFINE-FILE-INFO READTABLE "INTERLISP" PACKAGE "INTERLISP")

(DEFINE-FILE-INFO READTABLE "XCL" PACKAGE "XCL")

のように書いてファイルでのLisp方言とリードテーブルを切り換えることができたようです。
前者は、Interlispのリードテーブルを用いてInterlispパッケージで読み込み、後者は、Xerox Common Lispのリードテーブルを用いてXCLパッケージで読み込みという具合。

 試してみた感じでは、InterlispのリードテーブルはCommon Lispの用にシンボルの大文字小文字を大文字に統一したりはしないようで、逆に大文字で書いてやる必要があるみたいです。
この辺りはファイルによってまちまちで、Interlisp-DではCommon Lispの環境も統合されていたため、Interlisp-Dの記述の中にCommon Lispの記述があったり、Common LispのリードテーブルでInterlispのコードを読み込んでみたりと、結構自由だったみたいです。

 あまりInterlispのコードも目にしないと思うので上記からgrepのコードを記載してみます。
記法の簡単な解説ですが、

  • (* ...)がコメント
  • []は超括弧。対応した[]同士で閉じるか、開いた(を]一つで全部閉じる
  • rpaqqは、defvarみたいなもの
  • 関数の定義は、defineq(LISP 1.5のdefineの流儀)
  • bindというのは、Common LispのLOOPの元になったFOR。LOOPでいうLOOPキーワードを関数名として利用することもできたので、bindから書かれています(LOOPでいうと、(with foo x in ...)と書いているようなもの

というところです。

 スタイルの特徴としては、Interlisp-DはSmalltalkのようにイメージ指向なためファイルを編集するということがあまりありませんでした。(もちろん書き出すことは可能です。)
コードの整形や、日付等のコメントの挿入も自動でやってくれるため、そんな雰囲気がコードにも出ているかなと思います。

(FILECREATED "14-May-86 08:04:43" {DSK}<LISPFILES>GREP.;1 2502   

      changes to:  (FNS DOGREP)

previous date: " 5-Mar-86 12:15:18" {DANTE}<LISPNEW>LISPUSERS>GREP.;1)

(* Copyright (c) 1984, 1985, 1986 by Xerox Corporation. All rights reserved.)

(PRETTYCOMPRINT GREPCOMS)

(RPAQQ GREPCOMS ((FNS DOGREP GREP PHONE) (FILES BSEARCH) (INITVARS (PHONELISTFILES)))) (DEFINEQ

(DOGREP [LAMBDA (STR FILES) (* Newman "14-May-86 08:04")

(* * Originally coded by Larry Masinter.)

(* * No longer permanently modifies the DSPFONT when DSPFONT is not the same as the DEFAULTFONT. -DVN "14-May-86 08:03:59")

(if (LISTP FILES) then (for FILE in FILES do (DOGREP STRS FILE)) elseif (STRPOS "*" FILES) then (DOGREP STRS (DIRECTORY FILES NIL "*" "")) else (RESETLST (INFILE FILES) (RESETSAVE NIL (LIST (QUOTE CLOSEF?) (INPUT))) (RESETSAVE NIL (LIST (QUOTE DSPFONT) (DSPFONT))) (bind FOUND for STR inside STRS do (SETFILEPTR NIL 0) (bind POS while (SETQ POS (FFILEPOS STR NIL NIL NIL NIL NIL UPPERCASEARRAY)) do (OR FOUND (PROGN (PRINTOUT NIL T .FONT COMMENTFONT "(from " (INPUT) ")" .FONT DEFAULTFONT) (SETQ FOUND T))) (COPYCHARS NIL T (OR (BFILEPOS [CONSTANT (MKSTRING (CHARACTER (CHARCODE CR] (INPUT) 0 POS) 0) POS) (DSPFONT BOLDFONT) [COPYCHARS NIL T POS (SETQ POS (IPLUS POS (NCHARS STR] (DSPFONT DEFAULTFONT) (COPYCHARS NIL T POS (ADD1 (FILEPOS (CHARACTER (CHARCODE CR)) NIL POS])

(GREP (LAMBDA (STRS FILES) (* lmm " 1-Apr-85 15:27") (RESETLST (DOGREP STRS FILES))))

(PHONE [LAMBDA (NAME) (* lmm " 5-Mar-86 12:14") (GREP NAME (OR PHONELISTFILES (PROMPTFORWORD "Name of directory file: "]) ) (FILESLOAD BSEARCH)

(RPAQ? PHONELISTFILES ) (PUTPROPS GREP COPYRIGHT ("Xerox Corporation" 1984 1985 1986)) (DECLARE: DONTCOPY (FILEMAP (NIL (392 2368 (DOGREP 402 . 2000) (GREP 2002 . 2091) (PHONE 2093 . 2366))))) STOP

 さらについでに、上記のqeditというリストで作ったキューをGUIで操作できるという謎のプログラムを起動したスクリーンショットを載せてみます。

qedit-il

まとめ

 今回は、medley/miscを紹介してみました。
medley/miscは、かなり雑多なファイルの寄せ集めです。一個ずつ紹介すればネタも増えて嬉しいなと思いましたが、さすがに需要がないかと思い、まとめて紹介することにしました。
個別に紹介したいものがあれば、別途紹介記事を書くかもしれません。

Older entries (1753 remaining)