Rainbow for Common Lisp 作りました
February 19, 2013 at 11:55 PM | categories: ruby, common lisp |昨日のテンプレを流用して今日はcl-rainbowという地味なライブラリの宣伝をします。
https://github.com/taksatou/cl-rainbow
cl-rainbowとは、rubygemにあるrainbowをCommon Lispに移植したものです。 これを使うとターミナルの出力を簡単に色付けできます。
インストール
現在(2013-02-19) quicklisp登録申請中です。登録されれば以下でインストールできます。
(ql:quickload 'cl-rainbow)
使い方
以下のように使います。
(setf cl-rainbow:*enabled* t) (print (cl-rainbow:color :red "red string")) (print (cl-rainbow:color #x5599ff "rgb color code")) (loop for c across "RAINBOW" do (format t "~A" (cl-rainbow:color (random #xffffff) c)))
特に解説は不要だと思いますが、端末はカラー表示に対応している必要があります。
RGBのカラーコード指定すると、256色にダウンサンプルして一番近い色を表示します。
その他、例にはのせてませんが、端末が対応していれば斜体や太字にもできます。詳細はソースを見てください。
まとめ
ログ出力のときとかにちょっと便利なときがあるかもしれません。
リードマクロで文字列リテラルをごにょごにょして色付けできるようにするともうちょっと便利になるような気がするので、そのうちチャレンジしてみたいと思います。
フィードバック等ありましたらコメント頂けるとうれしいです。
LTSV for Common Lisp 作りました
February 18, 2013 at 08:30 PM | categories: ltsv, common lisp |ブームは過ぎ去ってしまいましたが、意外とまだなかったのでCommon LispのLTSVパーサつくりました。
https://github.com/taksatou/cl-ltsv
インストール
現在(2013-02-18) quicklisp登録申請中です。登録されれば以下でインストールできます。
(ql:quickload 'cl-ltsv)
使い方
以下のように使います。
CL-USER> (cl-ltsv:parse-line "host:127.0.0.1 ident:- user:frank") (("host" . "127.0.0.1") ("ident" . "-") ("user" . "frank")) CL-USER> (with-input-from-string (ss "host:127.0.0.1 ident:- user:frank host:127.0.0.1 ident:- user:jane host:127.0.0.1 ident:- user:john") (cl-ltsv:with-ltsv-from-stream (entry ss) (print entry))) (("host" . "127.0.0.1") ("ident" . "-") ("user" . "frank")) (("host" . "127.0.0.1") ("ident" . "-") ("user" . "jane")) (("host" . "127.0.0.1") ("ident" . "-") ("user" . "john")) NIL CL-USER> (cl-ltsv:alist-ltsv '(("host" . "127.0.0.1") ("ident" . "-") ("user" . "frank"))) "host:127.0.0.1 ident:- user:frank"
- cl-ltsv:parse-lineするとalistを返します
- cl-ltsv:with-ltsv-from-stream を使えば1行ずつパースしてループします
- cl-ltsv:alist-ltsv でalistからltsv形式の文字列に変換できます
まとめ
ライブラリにするほどでもなかった気はしますが、Common Lispには文字列のsplitが標準でついてなくてちょっと面倒に感じることもあったのでないよりはましかな、ということで作りました。
フィードバック等ありましたらコメント頂けるとうれしいです。
common lispのdefconstantについての注意点
February 09, 2013 at 05:15 PM | categories: common lisp |sbclでdefconstantすると以下のようなエラーがおきたりおきなかったりして不思議に思っていた。
The constant CL-GEARMAN::+REQUEST-MAGIC+ is being redefined (from #(0 82 69 81) to #(0 82 69 81)) [Condition of type DEFCONSTANT-UNEQL] See also: Common Lisp Hyperspec, DEFCONSTANT [:macro] SBCL Manual, Idiosyncrasies [:node] Restarts: 0: [CONTINUE] Go ahead and change the value. 1: [ABORT] Keep the old value. 2: [TRY-RECOMPILING] Recompile protocol and try loading it again 3: [RETRY] Retry loading FASL for #<CL-SOURCE-FILE "cl-gearman" "src" "protocol">. 4: [ACCEPT] Continue, treating loading FASL for #<CL-SOURCE-FILE "cl-gearman" "src" "protocol"> as having been successful. 5: [ABORT] Give up on "cl-gearman" --more-- Backtrace: 0: (SB-C::%DEFCONSTANT ..) 1: (SB-FASL::LOAD-FASL-GROUP ..) 2: ((FLET SB-THREAD::WITH-RECURSIVE-LOCK-THUNK :IN SB-FASL::LOAD-AS-FASL)) 3: ((FLET #:WITHOUT-INTERRUPTS-BODY-88874 :IN SB-THREAD::CALL-WITH-RECURSIVE-LOCK)) 4: (SB-THREAD::CALL-WITH-RECURSIVE-LOCK ..) 5: (SB-FASL::LOAD-AS-FASL ..) 6: ((FLET SB-FASL::LOAD-STREAM :IN LOAD) ..) 7: (LOAD ..) 8: (SB-IMPL::%MAP-FOR-EFFECT-ARITY-1 ..)
先日公開したcl-gearmanでこれが発生していてしまい原因がわからずそのまま放置していたのだけど、以下のforumを発見した。
http://www.lispforum.com/viewtopic.php?f=33&t=4088
It's not a bug (in SBCL). The value in a DEFCONSTANT form is restricted to being something that's EQL to itself each time it's evaluated (that's horrible phrasing, I know), so using a vector is illegal (that is, you can use a vector, but you have to make sure you return the same vector each time -- so you can't use VECTOR or #(...) for the value).
DEFCONSTANTフォームの値はそれが何度評価されてもEQLになるようなものでなければならないらしい。 なので、vectorをDEFCONSTANTでバインドすることは可能だけど、DEFCONSTANTフォームの値の場所にVECTOR や #(...)で記述したフォームを書くことはできない。
CLtL2にもちゃんと書いてあった。
defconstantはdefparameterに似ているが、名前の値が固定されていることを前提としており、コンパイラは、コンパイルされるプログラムでの値について仮定を置くことが許されている。 (...中略...) コンパイラは置き換えたオブジェクトのコピーが定数の実際の値とeqlになるように注意しなければならない。たとえば、コンパイラは数のコピーは自由に作ってもよいが、値がリストであるときは十分に注意しなければならない。
なるほど。
gearmanクライアントライブラリ cl-gearman
December 16, 2012 at 05:30 PM | categories: gearman, common lisp |この投稿はCommon Lisp Libraries Advent Calendar 2012の16日目の記事です。
GearmanをCommon Lispから使いたかったのですが、既存のものが見付からなかったのでcl-gearmanというものをつくってみました。というわけで紹介、もとい宣伝をさせてもらおうと思います。
Gearmanとは
今更感はありますが、Gearman自体について簡単に説明しておきます。
Gearmanとは時間のかかる処理を複数のコンピュータに振り分けるように設計されたオープンソースのアプリケーションフレームワークです。Gearmanを利用するアプリケーションでは、client, job server, workerという3つの要素が存在します。 それぞれの役割は以下の通りです。
- job server: clientから受けとったジョブを適切なworkerに渡す
- client: ジョブを生成してjob serverに送信する
- worker: job serverを経由して、clientによってリクエストされたジョブを実行してそのレスポンスを返す
cl-gearmanは、clientとjob server間、及びworkerとjob server間のプロトコルを抽象化したライブラリです。
余談ですが、Gearmanはデータ永続化をしないものだとずっと思っていたのですがmysqlやsqliteに永続化できます。 ジョブキューを使うなら以前はTheSchwartzという選択肢もありましたが、今はGearmanでほとんどの場合に対応できるのではないでしょうか。
インストール
まだquicklispに登録されていないので、githubからソースコードをダウンロードして下さい。(後日申請予定)
https://github.com/taksatou/cl-gearman
cd ~/quicklisp/local-projects
git clone https://github.com/taksatou/cl-gearman.git
使い方
以下サンプルコードです
client
submit-jobはjob serverにジョブを送信し、workerがそれを完了するまで待機します。workerが処理を完了するとその返り値が文字列で返されます。
CL-USER> (cl-gearman:with-client (client "localhost:4730") (format t "~a~%" (cl-gearman:submit-job client "hello")) (format t "~a~%" (cl-gearman:submit-job client "echo" :arg "foo))) hello foo NIL
以下のようにしてバックグランドでジョブを実行することもできます。バックグランドでジョブを実行するとjobオブジェクトが即座に返されます。 そのjobオブジェクトをつかって、ジョブのステータスを取得することができます。以下の例では見辛いですが、priorityを付けることでジョブの実行順を多少は制御できます。
CL-USER> (cl-gearman:with-client (client "localhost:4730") (let* ((job1 (cl-gearman:submit-background-job client "sleep" :arg "1")) (job2 (cl-gearman:submit-background-job client "sleep" :arg "1" :priority :low)) (job3 (cl-gearman:submit-background-job client "sleep" :arg "1" :priority :high)) (jobs `(:medium ,job1 :low ,job2 :high ,job3))) (dotimes (i 5) (loop for (k v) on jobs by #'cddr do (format t "~a: ~a~%" k (cl-gearman:get-job-status client v))) (sleep 1)))) MEDIUM: (JOB-HANDLE H:hostname:109 IS-KNOWN 1 IS-RUNNING 1 PROGRESS NAN) LOW: (JOB-HANDLE H:hostname:110 IS-KNOWN 1 IS-RUNNING 0 PROGRESS NAN) HIGH: (JOB-HANDLE H:hostname:111 IS-KNOWN 1 IS-RUNNING 0 PROGRESS NAN) MEDIUM: (JOB-HANDLE H:hostname:109 IS-KNOWN 0 IS-RUNNING 0 PROGRESS NAN) LOW: (JOB-HANDLE H:hostname:110 IS-KNOWN 1 IS-RUNNING 0 PROGRESS NAN) HIGH: (JOB-HANDLE H:hostname:111 IS-KNOWN 1 IS-RUNNING 0 PROGRESS NAN) MEDIUM: (JOB-HANDLE H:hostname:109 IS-KNOWN 0 IS-RUNNING 0 PROGRESS NAN) LOW: (JOB-HANDLE H:hostname:110 IS-KNOWN 1 IS-RUNNING 0 PROGRESS NAN) HIGH: (JOB-HANDLE H:hostname:111 IS-KNOWN 1 IS-RUNNING 1 PROGRESS NAN) MEDIUM: (JOB-HANDLE H:hostname:109 IS-KNOWN 0 IS-RUNNING 0 PROGRESS NAN) LOW: (JOB-HANDLE H:hostname:110 IS-KNOWN 1 IS-RUNNING 1 PROGRESS NAN) HIGH: (JOB-HANDLE H:hostname:111 IS-KNOWN 0 IS-RUNNING 0 PROGRESS NAN) MEDIUM: (JOB-HANDLE H:hostname:109 IS-KNOWN 0 IS-RUNNING 0 PROGRESS NAN) LOW: (JOB-HANDLE H:hostname:110 IS-KNOWN 0 IS-RUNNING 0 PROGRESS NAN) HIGH: (JOB-HANDLE H:hostname:111 IS-KNOWN 0 IS-RUNNING 0 PROGRESS NAN) NIL
worker
workerはadd-abilityで実行できるジョブとそのハンドラをあらかじめ登録する必要があります。 ハンドラは2つの引数をとる関数で、第一引数はclientからのデータ、第二引数はjobオブジェクトです。 返り値はprincでフォーマットした文字列としてclientに渡されます。workを実行するとジョブが割り当てられるまでブロックし、1つのジョブの実行が完了すると戻ります。
(cl-gearman:with-worker (worker "localhost:4730") (cl-gearman:add-ability worker "hello" #'(lambda (arg job) "hello")) (cl-gearman:add-ability worker "echo" #'(lambda (arg job) arg)) (cl-gearman:add-ability worker "sleep" #'(lambda (arg job) (sleep (parse-integer arg)) (format nil "job:~A finished~%" job))) (loop do (cl-gearman:work worker)))
エラーハンドリング
ジョブキューを使う上で悩ましいことの一つはエラー処理だと思いますが、Common Lispのコンディションシステムを使えば柔軟に対応できます。 workerのハンドラでは、skip-job, abort-job, retry-job の3パターンのリトライをサポートしています。
例えば、
(cl-gearman:with-worker (worker "localhost:4730") (cl-gearman:add-ability worker "error" #'(lambda (arg job) (error "something wrong"))) (loop do (handler-bind ((error #'(lambda (c) (invoke-restart 'cl-gearman:skip-job)))) (cl-gearman:work worker))))
のようにしておけば、エラーが発生したjobを無視することができます。 abort-jobはclientに失敗を通知します。retry-jobは名前の通りハンドラを再度実行します。
対応する処理系
メインに開発を行った環境は ubuntu 12.04, sbcl 1.0.55.0.debian です。 一応以下の処理系で動作確認しました
- sbcl 1.0.55.0.debian
- clisp 2.49
- clozure cl 1.8-r15286M
ffi系のライブラリには依存してないので比較的動かしやすいとは思いますが、動かなければ教えて下さい。
まとめ
以上、拙作のcl-gearmanを紹介しました。Common Lispを始めてまだ半年足らずなのでおかしいところがあるかと思いますが、フィードバックを頂けるとうれしいです。
cl-frontcodingをつくってみた
November 10, 2012 at 08:30 PM | categories: algorithms, common lisp |先週くらいに読んだWEB+DB PRESS Vol.42 に載っていたFront Coding という圧縮アルゴリズムを実装してみました。
http://d.hatena.ne.jp/naoya/20080914/1221382329 のパクりです。
ソースはhttps://github.com/taksatou/cl-frontcodingです。
学習目的でつくったので実用的なライブラリではないですが、CLOSやマクロを使いつつパッケージ作成〜テストまで一通りやりました。
CLOSもマクロも基本的な使い方をするだけなら意外と簡単でした。
CLOSとかマクロは本を読んでもいまいちよくわからない上に、深淵なイメージが膨らんで心理的ハードルがあがってしまうだけなので、よくわからないなりになにか作ってみると理解が進んでいいと思います。
About Me
mojavy |
Recent posts
95/5 Mbps とは
(August 30, 2015 at 04:22 PM)組み込み用プログラミング言語のパフォーマンス比較
(April 21, 2015 at 01:10 AM)最近読んだ本
(April 05, 2015 at 01:23 PM)Phabricatorを使ったワークフローについて
(March 02, 2015 at 08:55 PM)dnsimpleでダイナミックDNSをつかう
(December 23, 2014 at 08:02 PM)www2014のアドテク関連のResearch Trackメモ
(October 06, 2014 at 09:05 PM)flappymacs がMELPAに登録されました
(July 16, 2014 at 01:07 AM)EmacsでFlappy Birdっぽいもの書きました
(July 10, 2014 at 08:01 PM)
Recent Popular posts
Popular posts
Categories
- C (rss) (3)
- R (rss) (1)
- adtech (rss) (1)
- advent calendar (rss) (2)
- algorithms (rss) (2)
- android (rss) (2)
- aws (rss) (1)
- blog (rss) (2)
- blogofile (rss) (3)
- books (rss) (1)
- c++ (rss) (1)
- chef (rss) (4)
- common lisp (rss) (10)
- debian (rss) (2)
- dns (rss) (1)
- elasticsearch (rss) (1)
- elf (rss) (1)
- elisp (rss) (1)
- emacs (rss) (5)
- english (rss) (1)
- game (rss) (2)
- gearman (rss) (1)
- git (rss) (1)
- github (rss) (1)
- gitlab (rss) (1)
- golang (rss) (2)
- history (rss) (1)
- impress.js (rss) (1)
- internet (rss) (1)
- ios (rss) (3)
- jekyll (rss) (1)
- jenkins (rss) (1)
- linux (rss) (4)
- lisp (rss) (2)
- ltsv (rss) (1)
- lua (rss) (1)
- mac (rss) (3)
- mach-o (rss) (1)
- memo (rss) (2)
- mustache (rss) (1)
- note (rss) (1)
- objective-c (rss) (4)
- os (rss) (1)
- osx (rss) (2)
- others (rss) (1)
- paco (rss) (1)
- pdf (rss) (1)
- php (rss) (2)
- postfix (rss) (1)
- programming (rss) (12)
- project management (rss) (1)
- python (rss) (5)
- quicklinks (rss) (6)
- raspberry pi (rss) (2)
- redmine (rss) (1)
- reveal.js (rss) (1)
- ruby (rss) (10)
- sbcl (rss) (2)
- security (rss) (1)
- shell (rss) (2)
- smtp (rss) (1)
- solr (rss) (1)
- statistics (rss) (2)
- tips (rss) (10)
- tmux (rss) (3)
- toml (rss) (1)
- tools (rss) (1)
- twitter (rss) (1)
- ubuntu (rss) (1)
- unix (rss) (5)
- v8 (rss) (1)
- web (rss) (7)
- xcode (rss) (1)
- zeromq (rss) (2)
Archives
- August 2015 (1)
- April 2015 (2)
- March 2015 (1)
- December 2014 (1)
- October 2014 (1)
- July 2014 (3)
- March 2014 (6)
- February 2014 (4)
- November 2013 (3)
- October 2013 (4)
- September 2013 (2)
- July 2013 (2)
- June 2013 (2)
- May 2013 (1)
- April 2013 (6)
- March 2013 (3)
- February 2013 (8)
- January 2013 (5)
- December 2012 (1)
- November 2012 (6)
- October 2012 (7)
- August 2012 (1)
- July 2012 (9)
- June 2012 (1)
- April 2012 (1)
- December 2011 (2)
- November 2011 (2)