#:g1

lowdownの紹介

Posted 2014-08-28 16:15:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の241日目です。

lowdownとはなにか

 lowdownは、Moritz Heidkamp氏作のChickenでMarkdownを扱うライブラリです。

パッケージ情報

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

インストール方法

$ sudo chicken-install lowdown

すれば、

(use lowdown)

(require-extension lowdown)

試してみる

 派生形式が色々とあるmarkdownですがlowdownは、MarkdownTest suite (version 1.0.3)には全部パスしているとのこと。
また、Schemeらしくsxml形式への変換もサポートしていたりします。

(markdown->html
 "### おはよう日本について
おはよう日本
")
;=> "<h3>おはよう日本について</h3>
;    <p>おはよう日本</p>#t"
;   #<parser-input-end>

(markdown->sxml "### おはよう日本について おはよう日本 ") ;=> ((h3 ("おはよう日本について")) (p "おはよう日本")) ; #<parser-input-end>

 用意されている関数は、

  • markdown->html
  • markdown->sxml*
  • markdown-sxml->html-sxml
  • markdown->sxml
  • markdown-html-conversion-rules*

のようなところ。

まとめ

 今回は、lowdownを紹介してみました。
lowdownは、Chicken製のブログシステムで使われたりしているようです。

onlispの紹介

Posted 2014-08-28 10:00:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の240日目です。

onlispとはなにか

 onlispは、ポール・グレアム氏のOn Lispに出てくるコードをLiam M. Healy氏がCLOCCの一部として纏めたものです。

パッケージ情報

パッケージ名onlisp
プロジェクトサイト CLOCC - Common Lisp Open Code Collection / Hg / [e6b24a] /src/onlisp/package.lisp

インストール方法

 CLOCCのプロジェクトサイトからダウンロードしてきて適当に導入します。

$ hg clone http://hg.code.sf.net/p/clocc/hg clocc-hg

で全体のソースも取得できます。
src/onlisp が目的のソースです。

試してみる

 onlisp-util.lispと、onlisp-app.lispに分かれていますが、onlisp-util.lispの方はユーティリティとして使えなくもない感じになっています。といっても本のコードを並べただけに近いので、利用に当ってもう少し整理する必要があるかなと思います。
パッケージ名は、onlisp等ではなく、何故かpaul-graham〈ニックネームはpg〉。

(pg:flatten (funcall (5am:gen-tree :size 10)))
;=>  (-9 5 7 -6 3 -9 -5 -4 0 3 8 2 5 9 2 5 0 -5 -7 2 7 3 -3 -7 5 -1 -6 -3 4 -6 -5 3
;     9 -2 -6 6 2 6 10 -7 7 6 7 -3 9 -3 8 10 -9 10 5 0 -6 3 -7 -1 -1 1 10 9 -10 3 9
;     9 -1 -1 9 -8 -1 -4 -4)

(pg:aif 3 pg:it) ;=> 3

(pg:mklist 42) ;=> (42)

まとめ

 今回は、onlispを紹介してみました。
On Lispで紹介されているユーティリティは色々なユーティリティライブラリに取り込まれていますが、パッケージとしてまとめて配布しているのは、CLOCCだけのようです。
折角なのでもうちょっと使い易くして欲しいところ。

Allegro CL: Flavorsの紹介

Posted 2014-08-27 14:50:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の239日目です。

Allegro CL: Flavorsとはなにか

 Allegro CL: Flavorsは、Allegro CLのFlavorsの実装です。

パッケージ情報

パッケージ名Allegro CL: Flavors
ドキュメントFlavors
Quicklisp×

インストール方法

 Allegro CL上で

(require :flavors)

とすれば利用可能です。

試してみる

 毎度お馴染のBankAccountです。

 Spice LispのFlavorsと全く同じコードも動きますが、(send self ...)が(send-self ...)と書けたりするので、そちらを使ってみています。

(require :flavors)

(defpackage :allegroflavors.demo (:use :cl :flavors) (:shadowing-import-from :flavors :defmethod :make-instance))

(cl:in-package :allegroflavors.demo)

(defflavor bank-account ((dollars 0)) () :initable-instance-variables :gettable-instance-variables :settable-instance-variables)

(defmethod (bank-account :deposit) (x) (send-self :set-dollars (+ (send self :dollars) x)))

(defmethod (bank-account :withdraw) (x) (send-self :set-dollars (max 0 (- (send self :dollars) x))))

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

(send *my-account* :dollars) ;=> 200 (send *my-account* :deposit 50) ;=> 250 (send *my-account* :withdraw 100) ;=> 150 (send *my-account* :withdraw 200) ;=> 0

(defflavor stock-account ((num-shares 0) (price-per-share 30)) (bank-account) :initable-instance-variables :gettable-instance-variables :settable-instance-variables)

(defmethod (stock-account :set-dollars) (x) (setq num-shares (/ x price-per-share)) (send-self :dollars))

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

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

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

(send *my-stock* :set-dollars 600) ;=> 600

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

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

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

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

まとめ

 今回は、Allegro CL: Flavorsを紹介してみました。
Allegro CLでは、過去のコードとの互換性の為に用意しているようですが、それもなかなか凄いような気がします。
Flavorsも実装が色々あり、Flanz LispもFlavorsはMITのLispマシンからの移植版が利用できたようです。もしかしたら、それが受け継がれているのかなと思い、パッケージ内のシンボルを眺めてみましたが、どうも結構MITのFlavorsとは違っているようなので、Allegro CLでは独自の実装となったのかもしれません。

ObjectLISPの紹介

Posted 2014-08-26 10:30:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の238日目です。

ObjectLISPとはなにか

 ObjectLISPは、Gary L. Drescher氏作の1984、5年頃に開発された今でいうプロトタイプベースのオブジェクト指向システムです。

パッケージ情報

パッケージ名ObjectLISP
Quicklisp×

インストール方法

にソースが転がっているので適当に移植します。
compiler-letと、Lispオブジェクトのアドレスを取得する関数が処理系にあれば、恐らく簡単に移植できると思います。
SBCLなら

(defun %pointer (obj)
  (sb-kernel:get-lisp-obj-address obj))

のようなところ。

試してみる

 ObjectLISPのマニュアルもネットに転がっていますが、知っている所は残念ながら現在リンク切れ。
代りに1985年頃にCommon Lispのオブジェクト指向システムを議論するメーリングリストにマニュアルのTeX原稿が流れていたので紹介してみます〈今のlatex等でも処理できます〉。

 ObjectLISPで良く知られている話としては、Common Lispに搭載されるオブジェクト指向システムが議論された時に、(New)Flavors、CommonLoops、CommonObjectsとObjectLISPで争った的な話がありますが、自分が眺める限りでは、ObjectLISP/LMIの人達にそんなにプッシュする気はなかったような気がしています。
ちなみに、やる気満々のXerox方面では、CommonLoopsのMOPを活用してObjectLISPを実装したとのこと。
また、ObjectLISPは、1986年位のMac用の処理系であるCorel CL=Macintosh Allegro CLでは、オブジェクト指向システムとして採用されていて、GUI関係での記述で専ら使われていた様子

 ということで毎度お馴染BankAccountを書いてみます。

プロトタイプベースなのでdefkindのようなものを使わなくてもmake-objしたものをoneof/kindofでコピーして作っていけますが、一応用意されているので下記の例では使ってみました。
特徴的な構文としては、askがありますが、これは、オブジェクトのボディ内で式が評価できる感じのものです。askのボディ内とdefobfunのボディ内ではインスタンス変数が取得できるのですが、元ネタがメソッド(dollars/set-dollars)をオーバーライドさせるのが肝みたいなので下記のコードではメソッドにしています。

(defpackage :objectlisp.demo
  (:use :cl :obj)
  (:shadowing-import-from :obj
                          . #.(intersection (*:list-external-symbols :obj)
                                            (*:list-external-symbols :cl)
                                            :test #'string=)))

(cl:in-package :objectlisp.demo)

(defkind =bank-account=)

(defobfun (exist =bank-account=) (&key* (dollars 0)) (have 'dollars dollars))

(defobfun (dollars =bank-account=) () dollars)

(defobfun (set-dollars =bank-account=) (x) (setq dollars x))

(defobfun (deposit =bank-account=) (x) (set-dollars (+ (dollars) x)))

(defobfun (withdraw =bank-account=) (x) (set-dollars (max 0 (- (dollars) x))))

(defparameter *my-account* (oneof =bank-account= 'dollars 200))

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

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

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

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

(defkind =stock-account= =bank-account=)

(defobfun (exist =stock-account=) (&key* (num-shares 0) (price-per-share 30)) (have 'num-shares num-shares) (have 'price-per-share price-per-share))

(defobfun (set-dollars =stock-account=) (x) (setq num-shares (/ x price-per-share)) (dollars))

(defobfun (dollars =stock-account=) () (* num-shares price-per-share))

(defparameter *my-stock* (oneof =stock-account= 'num-shares 10))

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

(ask *my-stock* (set-dollars 600)) ;=> 600

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

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

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

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

まとめ

 今回は、ObjectLISPを紹介してみました。
最初のプロトタイプベースの言語と言われるSelfが1980年代中期に誕生ということなので、ObjectLISPも最初期のものの一つなのではないでしょうか。

Spice Lisp: Flavorsの紹介

Posted 2014-08-24 15:50:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の237日目です。

Spice Lisp: Flavorsとはなにか

 Spice Lisp: Flavorsは、Steven Handerson氏作のSpice Lisp上のFlavorsの実装です。

パッケージ情報

パッケージ名Spice Lisp: Flavors
Quicklisp×

インストール方法

 Rutgers Common Lisp(TOPS-20 Common Lisp)のアーカイブの中にSpice Lispプロジェクトが配布していたFlavorsのファイルが埋もれていますので、適当に動かします。

 例のごとく、ANSI CLで動くようにしてみたものがありますので、良かったらどうぞ。

Quicklispのlocal-projectsに設置でもすれば、

(ql:quickload :spiceflavors)

で読み込めます。

FlavorsとCommon Lispについて

 現在のANSI Common Lispには、CLOSが含まれていることと、CLtL1の時代にはオブジェクト指向システムが含まれていなかったことから、CLOS以前にはオブジェクト指向システムはCommon Lispに搭載されていなかったと思う人が多いですが、実際のところは、1984〜6年当時のメジャーな処理系はCommon Lisp+Flavorsで処理系を配布/販売していて、Flavorsはほぼデファクトな存在でした。
主なところでは、

  • Spice Lisp
  • NIL
  • Lucid Common Lisp
  • VAX LISP
  • Allegro Common Lisp(の前身のExCL)
  • Symbolics
  • LMI

等です。ほぼCLtL1部分だけのKCLと、オブジェクト指向システムにはObject LISPを添付していたMCLにはFlavorsは付いてこなかった様子。ちなみにObject LISPの元祖はLMIなのでLMIにも含まれています。

試してみる

 今回もオブジェクト指向システムの紹介の度に書いているBankAccountというのを書いてみます。

 FlavorsとCLOSの主な違いといえば、どちらも多重継承ですが、Flavorsはマルチメソッドではありません。
また、Smalltalkのようなメッセージ送信が基本です。
さらに、Flavorsでは、インスタンス変数はメソッドのボディのスコープ中から参照できます。
今回のBankAccountでは、dollarsはメソッドがオーバーライドされるのでインスタンス変数としてアクセスしていませんが、price-per-share/num-sharesはインスタンス変数としてアクセスしてみています。

(defpackage :spiceflavors.demo
  (:use :cl :spiceflavors)
  (:shadowing-import-from :spiceflavors
                          . #.(intersection (*:list-external-symbols :spiceflavors)
                                            (*:list-external-symbols :cl)
                                            :test #'string=)))

(cl:in-package :spiceflavors.demo)

(defflavor bank-account ((dollars 0)) () :initable-instance-variables :gettable-instance-variables :settable-instance-variables)

(defmethod (bank-account :deposit) (x) (send self :set-dollars (+ (send self :dollars) x)))

(defmethod (bank-account :withdraw) (x) (send self :set-dollars (max 0 (- (send self :dollars) x))))

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

(send *my-account* :dollars) ;=> 200 (send *my-account* :deposit 50) ;=> 250 (send *my-account* :withdraw 100) ;=> 150 (send *my-account* :withdraw 200) ;=> 0

(defflavor stock-account ((num-shares 0) (price-per-share 30)) (bank-account) :initable-instance-variables :gettable-instance-variables :settable-instance-variables)

(defmethod (stock-account :set-dollars) (x) (setq num-shares (/ x price-per-share)) (send self :dollars))

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

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

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

(send *my-stock* :set-dollars 600) ;=> 600

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

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

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

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

この例を書いていて判明しましたが、インスタンス変数の初期値を継承してこないバグがあるようです…。
移植によるものなのか、そもそもこういう仕様なのかは調査してみたいと思いますが、Allegro CLに付属してくるFlavorsと、VAX LISPに付属のFlavorsでは初期値は継承してくるようです。
ちなみに、上記では、stock-accountのdollarsは、bank-accountのdollars変数にアクセスしないため問題なく動きます。

まとめ

 今回は、Spice Lisp: Flavorsを紹介してみました。
今となっては伝説のFlavorsですが、実装は結構あるようです。
手軽に試すとすれば、Allegro CLで(require :flavors)するのが一番かもしれません〈最新の9.0の試用版でも可能〉。

html-parserの紹介

Posted 2014-08-23 15:40:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の236日目です。

html-parserとはなにか

 html-parserは、Alex Shinn氏によるChicken用のHTMLのパーザです。HTMLをsxmlに変換することも可能。

パッケージ情報

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

インストール方法

$ sudo chicken-install html-parser

すれば、

(use html-parser)

(require-extension html-parser)

試してみる

 html-parserは、Oleg Kiselyov氏のSSAXパーザのような、きっちりとしていて拡張性のあるインターフェイスでありつつ、壊れていたりすることの多いウェブのHTMLも簡便に扱えることを目標に作られたHTMLパーザとのこと。
用意されているのは下記のような関数です。

  • make-html-parser
  • html->sxml
  • sxml->html
  • sxml-display-as-html
  • html-display-escaped-string
  • html-strip
  • html-tag->string
  • html-escape
  • make-string-reader/ci
  • html-attr->string

 こんな感じの一行野郎も簡単に書けます〈(use http-client html-parser sxpath sxpath-lolevel)した状態で〉。

(for-each (compose print sxml:string-value) ((sxpath "//li/a") (html->sxml (with-input-from-request "http://tips.cddddr.org/scheme/index.cgi?c=a" #f read-string))))
;>> CGI を作る
;>> CPUのエンディアンを調べる
;>> CPUのワードサイズを調べる
;>> HTML を処理する
;>> InterWikiName
;>> R5RS ライブラリを R6RS ライブラリに加工する
;>> R6RS と SRFI で非互換な点
;>> XML を処理する
;>> XPath を使う
;>> anaphoric if
;>> quasisyntax を使う
;>> ...
               

一応の解説ですが、逆引きSchemeの項目一覧ページからli要素を抜き出す、という処理です。

まとめ

 今回は、html-parserを紹介してみました。
ちょっとしたテキスト処理は一行野郎で頑張ることも多いと思いますが、ちょっと込み入った処理になると、Common LispやSchemeで書いた方が早かったりしますよね。

zsortの紹介

Posted 2014-08-22 14:00:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の234日目です。

zsortとはなにか

 zsortは、Jorge Tavares氏作のCommon Lispのシークエンス用のソートライブラリです。

パッケージ情報

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

インストール方法

(ql:quickload :zsort)

試してみる

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

 Common Lispには標準でsortとstable-sortが用意されていますが、どんなソートアルゴリズムかを選択することはできないので、色々なアルゴリズムのソートを用意してみました、というライブラリです。
現在のところ

  • counting-sort
  • insertion-sort
  • heapsort
  • merge-sort
  • quicksort
  • randomized-quicksort

が用意されています。
動作は下記のような感じです。

(let ((u (*:iota 100 100 -1)))
  (zsort:counting-sort u))
;=>  (1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
;     30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
;     56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
;     82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100)

(let ((u (*:iota 100 100 -1))) (zsort:heapsort u #'<)) ;=> (1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 ; 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 ; 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 ; 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100)

(let ((u (*:iota 100 100 -1))) (zsort:insertion-sort u #'<)) ;=> (1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 ; 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 ; 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 ; 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100)

(let ((u (coerce (*:iota 100 100 -1) 'vector))) (zsort:merge-sort u #'<)) ;=> #(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 ; 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 ; 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 ; 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100)

(let ((u (*:iota 100 100 -1))) (zsort:quicksort u #'<)) ;=> (1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 ; 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 ; 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 ; 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100)

(let ((u (*:iota 100 100 -1))) (zsort:randomized-quicksort u #'<)) ;=> (1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 ; 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 ; 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 ; 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100)

ちなみに、どういう訳かmerge-sortがvectorにしか対応してないみたいです。

まとめ

 今回は、zsortを紹介してみました。
色々なアルゴリズムが選択できるというのは、なかなか良いですね。

cl-csvの紹介

Posted 2014-08-21 14:30:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の233日目です。

cl-csvとはなにか

 cl-csvは、Edward Marco Baringer氏とRuss Tyndall氏作によるCSVのライブラリです。

パッケージ情報

パッケージ名cl-csv
Quicklisp
CLiKiCLiki: CL-CSV
Quickdocscl-csv | Quickdocs
CL Test Grid: ビルド状況cl-csv | CL Test Grid

インストール方法

(ql:quickload :cl-csv)

試してみる

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

(with-output-to-string (out)
  (cl-csv:write-csv (*:group (*:iota 100) 10)
                    :stream out))
;=>  "0,1,2,3,4,5,6,7,8,9^M
;    10,11,12,13,14,15,16,17,18,19^M
;    20,21,22,23,24,25,26,27,28,29^M
;    30,31,32,33,34,35,36,37,38,39^M
;    40,41,42,43,44,45,46,47,48,49^M
;    50,51,52,53,54,55,56,57,58,59^M
;    60,61,62,63,64,65,66,67,68,69^M
;    70,71,72,73,74,75,76,77,78,79^M
;    80,81,82,83,84,85,86,87,88,89^M
;    90,91,92,93,94,95,96,97,98,99^M
;    "

(with-input-from-string (in "0,1,2,3,4,5,6,7,8,9^M 10,11,12,13,14,15,16,17,18,19^M 20,21,22,23,24,25,26,27,28,29^M 30,31,32,33,34,35,36,37,38,39^M 40,41,42,43,44,45,46,47,48,49^M 50,51,52,53,54,55,56,57,58,59^M 60,61,62,63,64,65,66,67,68,69^M 70,71,72,73,74,75,76,77,78,79^M 80,81,82,83,84,85,86,87,88,89^M 90,91,92,93,94,95,96,97,98,99^M ") (cl-csv:read-csv in)) ;=> (("0" "1" "2" "3" "4" "5" "6" "7" "8" "9") ; ("10" "11" "12" "13" "14" "15" "16" "17" "18" "19") ; ("20" "21" "22" "23" "24" "25" "26" "27" "28" "29") ; ("30" "31" "32" "33" "34" "35" "36" "37" "38" "39") ; ("40" "41" "42" "43" "44" "45" "46" "47" "48" "49") ; ("50" "51" "52" "53" "54" "55" "56" "57" "58" "59") ; ("60" "61" "62" "63" "64" "65" "66" "67" "68" "69") ; ("70" "71" "72" "73" "74" "75" "76" "77" "78" "79") ; ("80" "81" "82" "83" "84" "85" "86" "87" "88" "89") ; ("90" "91" "92" "93" "94" "95" "96" "97" "98" "99"))

(with-input-from-string (in "0,1,2,3,4,5,6,7,8,9 10,11,12,13,14,15,16,17,18,19 20,21,22,23,24,25,26,27,28,29 30,31,32,33,34,35,36,37,38,39 40,41,42,43,44,45,46,47,48,49 50,51,52,53,54,55,56,57,58,59 60,61,62,63,64,65,66,67,68,69 70,71,72,73,74,75,76,77,78,79 80,81,82,83,84,85,86,87,88,89 90,91,92,93,94,95,96,97,98,99 ") (cl-csv:do-csv (row in) (print row))) ;>> ;>> ("0" "1" "2" "3" "4" "5" "6" "7" "8" "9") ;>> ("10" "11" "12" "13" "14" "15" "16" "17" "18" "19") ;>> ("20" "21" "22" "23" "24" "25" "26" "27" "28" "29") ;>> ("30" "31" "32" "33" "34" "35" "36" "37" "38" "39") ;>> ("40" "41" "42" "43" "44" "45" "46" "47" "48" "49") ;>> ("50" "51" "52" "53" "54" "55" "56" "57" "58" "59") ;>> ("60" "61" "62" "63" "64" "65" "66" "67" "68" "69") ;>> ("70" "71" "72" "73" "74" "75" "76" "77" "78" "79") ;>> ("80" "81" "82" "83" "84" "85" "86" "87" "88" "89") ;>> ("90" "91" "92" "93" "94" "95" "96" "97" "98" "99") ;=> NIL

 これらの他、行単位で読み書きする、read/write-csv-row、要素単位で読み書きする、read/write-csv-valueが用意されていますが、大体他のCSVを扱うライブラリと同じで、CSVをリストに変換してくれるので、後はリスト操作で好きなように処理するという感じです。
これらに加えて、行単位で処理するdo-csvも用意されていて、さらに、改行やクォート方法については変数でカスタマイズできます。

まとめ

 今回は、cl-csvを紹介してみました。
CLikiでは、CSVを扱うお勧めライブラリとしては、このcl-csvが挙げられています。

どの辺りが良いのかの理由は書いてありませんが、多分、他より良いのでしょう。

stalinの紹介

Posted 2014-08-20 09:45:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の232日目です。

stalinとはなにか

 chicken-stalinは、Jeffrey Mark Siskind氏作の強い最適化を特長とするR4RSのコンパイラをFelix Winkelmann氏がChickenに移植したものです。

パッケージ情報

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

インストール方法

$ sudo chicken-install stalin

すれば、

$ chicken-stalin -copt -O2 -On file.scm

のような感じでSchemeのソースをコンパイルできます。

試してみる

 Stalinは単体でもDebianのパッケージ等でもインストールできますが、Chicken版のstalinは、文字列中の\n、\t、\eを使えるように拡張し、srfi-0のサポートも追加されています。

(define (fib n)
  (if (< n 2)
      n
      (+ (fib (- n 1))
         (fib (- n 2)))))

(display (fib 40)) (newline)

のようなファイル /tmp/fib.scm があれば、

$ chicken-stalin -copt -O2 -On /tmp/fib.scm

でコンパイルできて、

$ time ./fib                               
102334155
./fib  0.38s user 0.00s system 99% cpu 0.379 total

という感じです。
(fib 40)で0.38というのはSBCLだと

(setq sb-ext:*inline-expansion-limit* 360)

(defun fib (n) (declare (optimize (speed 3) (safety 0) (debug 0) (space 0)) (fixnum n)) (labels ((fib (n) (declare (fixnum n)) (if (< n 2) n (the fixnum (+ (fib (- n 1)) (fib (- n 2))))))) (declare (inline fib)) (fib n)))

(fib 40) ;=> 102334155 #|------------------------------------------------------------| Evaluation took: 0.374 seconds of real time 0.376000 seconds of total run time (0.376000 user, 0.000000 system) 100.53% CPU 1,007,460,264 processor cycles 3,840 bytes consed

Intel(R) Core(TM) i7-4600U CPU @ 2.10GHz |------------------------------------------------------------|#

位やらないと追い付けない感じです。

まとめ

 今回は、stalinを紹介してみました。
Stalinはやっぱり速いですね。

defrecの紹介

Posted 2014-08-19 06:20:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の231日目です。

defrecとはなにか

 defrecは、Robert Smith氏作の再帰する関数を定義するためのユーティリティです。

パッケージ情報

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

インストール方法

(ql:quickload :defrec)

試してみる

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

 といっても定義はdefrec一つのみです。
主に相互呼び出しの再帰関数の定義に用いることを意図しているようですが、defrecマクロがしていることは、ローカル関数を作って、それを大域関数の補助関数とする、というものです。
一度labelsで定義したものをfletで包み、それをまたdefunで大域定義としていますが、fletは何のためなのでしょう。

(defrec:defrec
  (fib (n)
    (fib1 n 1 0))
  (fib1 (n a1 a2)
    (cond ((zerop n) a2)
          ((= 1 n) a1)
          (T (fib1 (1- n) (+ a1 a2) a1)))))
;==>
(LABELS ((FIB (N)
           (FIB1 N 1 0))
         (FIB1 (N A1 A2)
           (COND ((ZEROP N) A2) ((= 1 N) A1) (T (FIB1 (1- N) (+ A1 A2) A1)))))
  (FLET ((#:FIB1221 (N)
           (FIB N))
         (#:FIB11222 (N A1 A2)
           (FIB1 N A1 A2)))
    (DECLARE (INLINE #:FIB1221 #:FIB11222))
    (DEFUN FIB (N) (#:FIB1221 N))
    (DEFUN FIB1 (N A1 A2) (#:FIB11222 N A1 A2)))
  '(FIB FIB1))

(fib 100) ;=> 354224848179261915075

 ドキュメントにあるコード例をみて思いましたが、多分

(labels ((even (x)
           (declare (type unsigned-byte x))
           (if (zerop x)
               t
               (odd (1- x))))
         (odd (x)
           (declare (type unsigned-byte x))
           (if (zerop x)
               nil
               (even (1- x)))))
  (setf (values (fdefinition 'even)
                (fdefinition 'odd))
        (values #'even #'odd)))

 のようなものを、

(defrec:defrec
  (even (x)
    (declare (type unsigned-byte x))
    (if (zerop x) t (odd (1- x))))
  (odd (x)
    (declare (type unsigned-byte x))
    (if (zerop x) nil (even (1- x)))))

のように、すっきり書くことを意図しているのかなと思いました。

まとめ

 今回は、defrecを紹介してみました。
今回も一発物でした。even/oddのような関係の関数の定義は殆どないと思いますが、ローカル関数を定義しつつ大域でも呼び出したいような場合には便利かもしれません。

Older entries (1813 remaining)