株式会社はてなに入社しました

| 【1分で読めるよ!】 | コメント(1) | トラックバック(0)

 本日付けで株式会社はてなの京都本社にWebアプリケーションエンジニアとして入社しました。これからはid:nitro_idiotとして活動します。

 京都に引っ越さなければいけなかったため、お世話になった人たちには早めに個別でお話をして回りました。けれど、今月は引越し準備や送別会などが重なり、何人かは会う機会のないまま京都に来てしまいました。ごめんなさい。

 皆に伝えて回ったときに印象的だったのは、人によって「え、はてな…?」と首をかしげる人から、「いいなー」という人まで幅広くいたことです。後者はさらに「はてないいなー」という人と「京都いいなー」という人に類別されます。共通するのは、皆、はてなの状況となぜはてなを選んだのかを知りたがったことでしょうか。

「はてなは良い会社なんですか」
「それは入ってみないとわかりません」

 僕は昔、高校の転入面接のとき「この学校に転入したら何をしたいですか?」と聞かれて、「受かってもないのにその後のことを聞かれても答えようがないです」と答えたことがあります。面接官たちは苦笑いしてそれ以上追求しませんでしたが、その反応からあまり良い答えではなかったと気づきました。筆記試験で自信をなくしていた僕は、「落ちるんじゃないか」という後向きな考えに囚われていたのです。実際は学力は及第点だったのに、面接の悲観的な態度が原因で再評価という皮肉な結果だったのですが。

 そのときから、僕の偏執的な心配性は変わっていないようです。面接のときに「はてなに入ったら何をしたいですか?」と聞かれて答えに迷った挙句、入社した自分の姿を想像できずに「入ってみないとわからない」と正直に答えてしまいました。本当に、受かってよかったです。

 とは言え、楽観的な考えがなければ転職して京都に引っ越すなんていう決断もしていないかもしれません。仕事の面では最近Perlを書いてないけど徐々に慣れていけばいいかーと思っているし、挨拶なしで別れてしまった人たちもきっとまた会うこともあると思います。

 自分がいることで、はてながさらに魅力的な企業になるよう努力します。今後もよろしくお願いします。

今月でアリエル・ネットワークを退職します

| 【2分で読めるよ!】 | コメント(2) | トラックバック(0)

 ビールが好きです。でも、家でビールばかり飲んでいると出費がかさみます。考えた末、今月から禁ビールを始めました。

 しかし、2週間ほど続いたある日に暑さに負けてビールを飲んでしまいました。半端な決意では何事も続かないものです。

 私事ですが、今月末でアリエル・ネットワークを退職することになりました。今日が最終出社日で、持ちチケットがなくなったので会社でブログを書いているところです。去年の5月に中途入社してから今月を含めて16ヶ月いたことになります。

 学生アルバイトとして働いていた手嶋屋も含めると、1年ちょっとで2回会社をやめたことになります。会社を短期間でやめて職を転々としたり、いとも簡単に禁ビールに失敗したりしていると、僕が思う以上に周りの人間に心配されました。特にCTOの井上さんにはちょっとした説得もされました。

井「もう1年頑張りませんか」
僕「いや、これ以上勤めていても何か力になれそうにもないので」
井「せっかくアリエルに入ったので、何か残して去ってもらいたかったんですが」

 アリエルでは割と自由な立ち位置でやらせてもらっていて、この一年は趣味のプログラムを中心にアリエルの名を広く知らしめる活動をしてきました。

 ただ、会社に残せたものは何もありません。Javaは結局書けず仕舞いだし、入社時に一番期待されていた「会社の文化を変えること」も成し遂げられていません。

 なので、僕はこの退社を敗北と捉えています。僕が入社してからも会社の居心地は単調に悪くなり、自分の意図しない方向に進むゆっくりとした変化は、気づけば自分の居場所のなさを感じるまでになっていました。退社の意思を固めてからは、自分一人では何も変えられないという無力さをずっと噛み締めています。

 「もうプログラマをやめて、崖の上で子どもをキャッチする仕事をするんだ…」と冗談めかして言ったりもしました。けれど、プログラム以外何もできない人間です。まだ比較的若いというのもあります。一度仕切りなおして、一人のエンジニアとして静かに人生を生き直すつもりです。勝手ではありますが、そっと見守っておいてください。

 最後に、Modern Common Lisp周りに期待されている方々へ。Modern Common Lispはこれまで通り松山さん(@m2ym)と2人で更新していきます。新しいライブラリの開発は減るかもしれませんが、ClackCavemanなどのCLライブラリの開発は続けるつもりです。せめて大好きなCommon Lispの文化だけは変えてみせたいですからね。

 禁ビールはもはやどうでもいいです。

SoftwareDesign連載寄稿「Modern Common LispとEmacs」

| 【1分で読めるよ!】 | コメント(1) | トラックバック(1)

 久しぶりにアリエルで連載している、Software Designの「Emacsのトラノマキ」に寄稿しました。

 タイトルは「Modern Common LispとEmacs」です。今月から2回に渡って最近のCommon Lisp周りについてまとめています。原稿を読んだ岩永さんに「Emacs関係ねーじゃん!!」って言われたけど気にしません。

 第1回の9月号は、主にEmacsでの環境設定を解説しています。内容の多くはModern Common Lispからの抜粋なので、ブログの更新を追っている方には必要ないかもしれません。逆にブログを購読していない人や、細切れになったブログ記事を一つの流れのある文章にまとめてあることに意義を感じる人にはいいかもしれないです。

 発売は明日(8月18日)です。Common Lispが雑誌に載ることもそうそうないはずなので興味のある人は立ち読みくらいしてください。

Emacsからnode.jsやChromeとSocket通信

| 【5分で読めるよ!】 | トラックバック(0)

 JavaScriptを書いています。普段Common Lispしか書いていないように見せかけていますが、JavaScriptを書いています。生きるためには仕方のないことです。それほど嫌いな言語ではないとは言え、書いているときはやはりCommon Lispが恋しいです。

 Lispは言語としての表現力が強力であることは広く知られている事実ですが、Lispのメリットはそれだけではありません。もう一つのメリットは、走っているプロセスのREPLに直接アクセスして動的に関数定義などを変更できることです。「EmacsでC-c C-c → ブラウザ更新 → EmacsでC-c C-c → ブラウザ更新」の開発効率は、一度慣れると離れがたいですよね。

 今日はJavaScriptを書いていました。いつものようにデプロイする度にChromeのコンソールからちまちま叩いていました。そんなとき、ふとEmacsからアクセスできないものかと検索しました。そして、「swank-js」というものを見つけました。

swank-js

 僕のリポジトリだし、まるで我が物かのようにドヤ顔で説明しますが、僕が作ったわけではありません。元はIvan Shvedunovさんが作ってたみたいです。更新が止まってて、最新のSocket.ioだと動かなかったのでforkしてパッチを当てて動くようにしました。パッチ当てついでの紹介と思ってください。

 コンセプトとしてはMozReplと同じ。WebSocketによる安定した通信と、クロスブラウザ対応が売りのようです。

インストール

 0. あらかじめ適当なディレクトリにクローンしてください。

$ cd ~/Programs/utils/
$ git clone git://github.com/fukamachi/swank-js

 1. node.jsnpmをインストールします。

$ brew install node
$ curl http://npmjs.org/install.sh | sh

 2. Socket.ioをインストールします。

$ npm install socket.io

 3. SLIMEをインストールします。ダウンロードしてload-pathの通ったところに置くだけです。

 4. slime-js.elのシンボリックリンクをSLIMEのcontrib/に置きます

$ ln -s ~/Programs/utils/swank-js/slime-js.el ~/.emacs.d/elisp/slime/contrib/

 5. .emacsに設定を追記します。

(require 'slime)
(slime-setup '(slime-repl slime-fancy slime-banner slime-js))

(global-set-key [f5] 'slime-js-reload)
(add-hook 'js2-mode-hook
          (lambda ()
            (slime-js-minor-mode 1)))

Emacsでnode.jsを使う

 1. swank-jsのディレクトリに移動し、以下のコマンドを実行します。

$ cd ~/Programs/utils/swank-js/
$ node swank.js

 2. EmacsでM-x slime-connect、Host: 127.0.0.1、Port: 4005

nodejs.png

 見慣れたSLIMEのインターフェースでちゃんと動いてます。

 もちろんjs2-modeでC-c C-cするとコードがREPLに送られて評価されます。

EmacsからブラウザのREPLにアクセス

 swank-jsはMozReplのようにブラウザと通信して、Emacsからブラウザコンソールにアクセスできます。ブラウザでアプリケーションを見ながらC-c C-cで動的にJavaScriptを変更することができます。

 ブラウザのREPLにアタッチは以下のページを開くだけで済みます。

 そして、SLIMEに戻って、,select-remoteと入力します。選択可能なプロセス一覧が出るので”node.js/direct”以外を選択してください。

chrome.png

 ちゃんとDOMにアクセスできました。console.logやalertもちゃんと動きます。

 もちろんFirefoxでも使えます。IEが動くマシンを持ってないのでIEは知らないです。

※追記: 以下のブックマークレットを使えば好きなページでattachできます。

 なんか素直にやるとうまくいかなかったのでsetTimeoutとか使ってしまいました。

 READMEには,target-urlで指定したサイトにproxy経由でattachできるみたいなことがi書いてあったけど動かなかった。

まとめ

 今日はJavaScriptをデバッグしたいがために初めてnode.jsを触ってみました。WebSocketは面白そうだったのでこれから機会を見つけて触ってみようと思います。

 JavaScriptはブラウザ上で動かさないといけないし、必要なライブラリのロードなども気を遣わなければいけませんでしたが、これで少しは気軽にコードを書き始められそうです。

 まあ、

  • あらかじめプロセスを走らせておかないといけない
  • オートコンプリートしたい
  • ブレーク貼りたい
  • そもそもClosure Compilerでコンパイルしてるとコンソールが使いものにならない

とか不満はまだあります。ブレークは、Emacs LispでCommon Lispのようなデバッガを実装すればいいのかもしれません。パッチは常にお待ちしています :P

 Emacs/JS使いは試してみてください。

(loop (incf love)) を最適化

| 【3分で読めるよ!】 | コメント(1) | トラックバック(1)
“while(1){LOVE++}”と書き込まれてる指輪があって、 そのソースは最適化でLOVEが消えてただの無限ループになる云々という話があったので検証。

 なんと無情なコンパイラ。効率化の果てに愛までも失ってしまうとは。

 試しにCommon Lispでも検証してみました。処理系はSBCL 1.0.29です。

CL-USER> (defun main ()
           (loop with love = 0
                 do (incf love)))
MAIN
CL-USER> (disassemble #'main)
; disassembly for MAIN
; 12763A36:       31D2             XOR EDX, EDX               ; no-arg-parsing entry point
;       38: L0:   BF04000000       MOV EDI, 4
;       3D:       E806C789F1       CALL #x4000148             ; GENERIC-+
;       42:       7302             JNB L1
;       44:       8BE3             MOV ESP, EBX
;       46: L1:   EBF0             JMP L0
;       48:       0F0B0A           BREAK 10                   ; error trap
;       4B:       02               BYTE #X02
;       4C:       18               BYTE #X18                  ; INVALID-ARG-COUNT-ERROR
;       4D:       4D               BYTE #X4D                  ; ECX
NIL

 ADDの代わりにGENERIC-+を呼んでいるようです。

 最適化してみます。

CL-USER> (declaim (optimize (speed 3) (safety 0) (debug 0)))
; No value
CL-USER> (defun main ()
           (loop with love = 0
                 do (incf love)))
MAIN
CL-USER> (disassemble #'main)
; disassembly for MAIN
; 127BE64A:       31D2             XOR EDX, EDX               ; no-arg-parsing entry point
;       4C: L0:   BF04000000       MOV EDI, 4
;       51:       E8F21A84F1       CALL #x4000148             ; GENERIC-+
;       56:       7302             JNB L1
;       58:       8BE3             MOV ESP, EBX
;       5A: L1:   EBF0             JMP L0
NIL

 GENERIC-+を呼んでいます。

 さらに型宣言をつけます。loveには限界ができてしまいますがこの際致し方ありません。まあ 536870911 (most-positive-fixnum) もあれば十分でしょう。

CL-USER> (declaim (optimize (speed 3) (safety 0) (debug 0)))
; No value
CL-USER> (defun main ()
           (let ((love 0))
             (declare (type fixnum love))
             (loop (incf love))))
MAIN
CL-USER> (disassemble #'main)
; disassembly for MAIN
; 1191F63A:       31C0             XOR EAX, EAX               ; no-arg-parsing entry point
;       3C: L0:   83C004           ADD EAX, 4
;       3F:       EBFB             JMP L0
NIL

 ADDに変わりましたがまだ愛は残っています。

 Common Lispは効率化の果てにも愛は失わないようです。素敵ですね。

参考

Common LispのModernなパッケージ論

| 【3分で読めるよ!】 | トラックバック(0)

 先日のブログで、Clackについて

Common Lispの醜い部分がどうすれば美しくなるか。どうすればコードがドキュメントになりうるのか。それを考え抜いた末生まれたのがClack。

と書きました。それを見てか、Clackの中身に興味を持った人もいるようです。けれども、僕が確認した限りではあまり良い反応はありませんでした。

 残念なのは、お互いの目的が違うための意見のすれ違いが起こったことです。僕は「読みやすさ」を最重要視しているにも関わらず「書きやすさ」の観点からの意見がありました。確かに僕が主張するスタイルは、作者にいくらかの負担を強いるものでしょう。注意を払わなければならないことも増えます。行数もわずかに増えるでしょう。けれど、「読みやすさ」は何よりも勝るはずです。そうでしょう?

 今回は、特に違いの目立つパッケージの使い方についてまとめます。

One package per one file

 Common Lispのプログラムにおいて、ファイルというのはあまり重要視されません。すべて読み込んでしまえば、どのファイルに書いてあるかなんてみんな忘れ去られてしまいます。なので、ファイルを分けて書くのは単純にプログラムをいくつかのセグメントに分けて見た目をよくしたいという目的でしかありません。

 奇妙なのが、その区分とは別で、読み込まれたあとにはプログラムは「パッケージ」によって分割されることです。ファイルを分けて書くという目的が、単にファイルをセグメント分けするためのものであるならば、それを実際のパッケージに分割して書かない理由があるでしょうか。僕が主張することは、1つのファイルには必ず1つのパッケージが関連付けられるスタイルです。

(in-package :cl-user)
(defpackage :style-guide.core
  (:use :cl))
(in-package :style-guide.core)

(cl-annot:enable-annot-syntax)

@export
(defun export-function ()
  ;; blah blah blah.
  )

(defun local-function ()
  ;; blah blah blah.
  )

 Clack.Utilにはこれをもう少しすっきり書くマクロがあります。

(clack.util:namespace :style-guide.core
  (:use :cl))

 大きなライブラリを書いているときは、いくつかのパッケージに分かれた関数をまとめて一つのインターフェイスとして提供したいこともあります。その場合は、メインのパッケージを、シンボルをまとめる目的で使えばいいです。たとえばCavemanならば、caveman.appcaveman.routeから必要なシンボルをimportしたcavemanというパッケージがあります。これにより、ユーザはcavemanパッケージだけを意識していればいいというわけです。

利点

 このスタイルは単なるアイデアではなく、いくつかの利点をもたらします。一つはプログラム内の各セグメントの依存関係がはっきりすることです。これは特に大きなプログラムでメリットになります。プログラム全体を一つの巨大なパッケージで囲ってしまうと、その一部だけを再利用したいときや、一部だけを取り除きたいときに影響がどの範囲まで及ぶのかわからなくなります。僕の考えでは、多くのCLプログラムが読みづらいのはこれが原因です。

 また、このメリットを最大化するために、defpackageでの:useも避けるべきです。Clackでは他のパッケージの関数が必要になれば:import-fromを積極的に使っています。コードを読んでいて、大量の:useによって、そのシンボルがどこからやってきたものなのか分からなかったことなんてないでしょうか。僕はそんな経験だらけです。僕は、誰かがClackを読んでいてそんな思いをすることに耐えられなかったのです。

まとめ

 このスタイルは実用を無視した空論ではありません。Clackはまさにこのスタイルが発生した最初のライブラリですし、その上に組まれたフレームワークのCavemanや、Clackの文化を後押しするcl-annotも同じスタイルを導入しています。

松山「(文章もそうだけど、)プログラムも”深町さんらしい”コードっていうのはあるだろうね。昔からのCLerとかが、Clackのコードを読んだら、たぶんビビると思うよ」

 読みやすさを検証したいならば、一度Clackのコードを見てみることをおすすめします。「コードがドキュメントです」というのは怠惰なOSSの風潮から生まれた、半ば飽きられたフレーズですが、Clackにおいては正に自信を持ってそう言うことができます。Clackのコードはドキュメントのように読みやすいです。もちろん、HTMLのドキュメントも用意しています。

僕はアリエルに入って何を生み出したか

| 【5分で読めるよ!】 | トラックバック(0)

 僕がアリエルに入ってから、今月で一年が経ちました。通常一年の振り返りは大晦日にすれば十分なものですが、アリエルの年度末ついでに振り返っておきます。

 僕はこの一年間、かつてないほどプログラムを書きました。短期間のうちに次々とプロダクトを生み出したために、不幸にも十分に紹介しきれていないプロダクトもあります。それもいずれModern Common Lispに書こうと考えていたのですが、見ての通りその筆も遅々としているのでここで紹介しておきます。

L5 (2010年5月)

 L5はアリエルに入ってすぐに作ったS式で記述するプレゼンツールです。Clojureで書かれています。Web+DB Press Vol.61ではこれに言及した記事を書かせていただきました。

 アリエルに入りたての頃、井上さんに声をかけられて、社内でClojure勉強会をすることになったのが発端です。アリエルの面接を受けたとき、最近はClojureをやっている、という話をしたためでしょうか、アリエルに入ってしばらくは”Clojureをやる人”という認識をされていたように思います。

 けれど、そのときまでにClojureで書いたものといえばAppEngine上で動くTwitterボット程度のものです。発表するなら事前に何か作っておきたいなぁと思ったときに考えたのがプレゼンツールでした。社内勉強会をした段階ではようやく見れる程度のものにすぎなかったものをGitHubでL5という名前で公開し、Tokyo.cljでちまちまと作りつづけ、なんとか今の形にまでなったものです。

 作り始めた理由が理由だけに、自分で使うことを開発の主目的でした。この一年、Shibuya.lisp、ありえるえりあ勉強会で発表しましたが、いずれもL5を使って資料を作ってきました。けれども最近になって、使ってくれた人の声もちらほら聞くこともあってうれしい限りです。

 この程度のプロダクトに裏話など不要でしょうが、L5は最初はScarecrowという名前でした。 L5になった理由は言うまでもなくS5由来です。

CL-TEST-MORE (2010年10月)

 再びCommon Lispに戻ってきた理由は今でははっきりしません。推測するに、おそらくJavaが嫌いだったのでしょう。副作用がないというフレコミのClojureも、Javaのライブラリを使いすぎると手続き的です。

 Common Lispに戻ってきて最初に作ったのがCL-TEST-MOREというテストライブラリでした。初めて一人で渡米し、ILC2010 @ Renoから意気揚々と帰国した次の日のこと、Shibuya.lisp Hackason #1でだらだらと作り上げたものです。

 このときの僕のCLのレベルは今思えばひどいもので、コードを見れば思わず苦笑するほどですが、最初に作ったCLライブラリということもあり、僕には愛着のあるものです。Quicklispに登録されたというだけで無邪気に喜んでいたくらいですから。

 もちろん、あとで作った僕のプロダクトはすべてこのCL-TEST-MOREでテストされています。

cl-markup (2010年12月)

 今こうして並べてみると、このプロダクトだけは他から浮いてみえます。理由の一つは、これが僕の必要から生まれなかったからでしょう。

 この時期、アリエルで松山さんがCommon LispでWebサービスを作ることになりました。それに辺り、松山さんはCLにまともなテンプレートエンジンがないことを嘆いていました。最も有名なのはご存知CL-WHOですが、驚くべきことにCL-WHOは埋め込んだ文字を自動でHTMLエスケープしてくれないのです。これはCL-WHOの造りに由来するところであり、マクロ展開時のぎりぎりのチューニングの結果生み出されていた歪みでした。

 cl-markupはそんな松山さんの嘆きに応えるために僕が作ったテンプレートエンジンです。CL-WHOのようにHTMLをS式で記述できる上に、より簡潔で美しいAPIを提供しています。そして、CL-WHOと遜色ないほどのチューニングを施してあります。ほとんどの静的記述はコンパイル時にwrite-stringにまで展開されます。

 その仕組みから、複雑なテンプレートを書くとコンパイルに時間がかかるという欠点があります。この欠点はSBCLで最も顕著になり、僕や松山さんがCCLに移行する発端となりました。

 cl-markupがQuicklispに登録されるまではそれほど時間はありませんでしたが、その後は今に至るまでブログやTwitterなどでまったく触れられることがなかったかわいそうなプロダクトです。理由は、これが完成してすぐ、僕はClackの開発に取りかかったからです。

Clack (2011年1月)

 Clackは今見返しても僕が生み出した最大の作品です。言い過ぎではないでしょう、これほど美しいCLプログラムを僕は見たことがありません。そして、この美しいプログラムが存在しなければ、のちに松山さんが作ったcl-annotも生まれ得なかったのではないかと思います。

 実を言うと、僕が最初に作ろうとしていたものはRailsでした。フレームワークの名前もSlinkyという名前でした。リポジトリを遡ればdefactiondefviewといったありきたりな名前のマクロが作られていた痕跡も見つかります。そんなSlinkyは元旦を越えた頃、野暮なコードの大部分を捨て去り、Clackへと生まれ変わったのです。

 ClackはPerlのPlackを参考に作られました。Plackと自分のコードを見比べて感じたことは、Common Lispのコードが他の言語の進化と調和していないことでした。最近のLLでは当たり前のようにプログラムの各コンポーネントの非依存化が進んでいます。疎結合は密結合より良しとされ、保守性もあがることは常識となっています。もちろんPerlでもそうです。

 しかし、Common Lispプログラムではパッケージをコンポーネントごとに分けるということすらされていません。パッケージが分かれていたとしてもいたずらにuse-packageする慣習から、そのシンボルがどこで生まれたものなのかも判別することが難しい状態です。

 そういったCommon Lispの醜い部分がどうすれば美しくなるか。どうすればコードがドキュメントになりうるのか。それを考え抜き、作っては大胆に壊すことを惜しげなく繰り替えして、6週間の苦悩の末完成に至ったのです。ドキュメントと自動テストも、あとから追加すればいい、などと妥協しなかったのも自信が持てる点です。

 Clackの偉大な点は、その実用性に止まりません。ClackはCommon Lisp界の新しい道を規程する象徴であり、それを辿る旅がModern Common Lispです。

Caveman (2011年2月)

 世に出たClackには、明らかにそれを使ったフレームワークの存在が不可欠でした。しかし、Clackが僕のブログで十分な反響を得たあと、途端に静かになるのを僕は見逃しませんでした。そのとき僕がしなければならないことは、誰かがClackを利用したフレームワークを作ることを期待する前に自分自身でCommon LispのWebフレームワークを作ることです。

 CavemanはCommon Lisp界のSinatraです。ディスパッチャ部分はFlaskに似ています。もちろんModelやViewに関して何も強制するものはありません。

まとめ

 手嶋屋にいる頃から僕は、「そろそろ知識を蓄えてばかりではいけない。何かを生み出さないと」という考えに言いようもない焦りを感じていました。常にそれを念頭に置いていたわけではないにせよ、こうして振り返った限りではそれを実現はできているようにも思えます。

 ただ、作るものに偏りがあるのも確かです。多くのWebサービスを生み出している人々と比べれば、ライブラリをいくつか書いた程度では比較にならないかもしれません。Lispが実用的なものを何一つ生み出していないなどとほざいている人には相手にもされないでしょう。

 そうすると、次の課題は今作った地盤を固めてさらに上を目指すことになるんでしょうか。あんまり地道な道のりは得意ではないけど、Lispでお金が生まれる日まではプログラミングに対するセンス・オブ・ワンダーを忘れないようにしよう。

4chan発のソートアルゴリズム"Sleep sort"をCommon Lispで

| 【6分で読めるよ!】 | コメント(3) | トラックバック(1)

 4chanで新しいソートアルゴリズムが発明されたようです。

Genius sorting algorithm: Sleep sort

 Bashなのでよくわからないですが、要素全部に対してスレッドを作り、その値分だけsleepするソートアルゴリズムのようです。

 スレッドではさらにC#、Perl、Scheme (Racket)、Cなどの実装が書かれています。

 ようやく退院したことだし、リハビリついでにCommon Lispで書いてみました。

Sleep sortをCommon Lispで

コマンドライン引数をとる

 一応処理系別で分岐させておく。

(defun args ()
  #+allegro (cdr (system:command-line-arguments))
  ; alisp -#! sleepsort.lisp 1 2 2 3
  #+sbcl (cdr sb-ext:*posix-argv*)
  ; sbcl --load sleepsort.lisp 1 2 2 3
  #+clisp ext:*args*
  ; clisp sleepsort.lisp 1 2 2 3
  #+ecl (cdr (member "--" (si:command-args)) :test #'string=)
  ; ecl -load sleepsort.lisp -- 1 2 2 3
  #+cmu ext:*command-line-application-arguments*
  ; cmucl -load sleepsort.lisp -- 1 2 2 3
  #+ccl (cdr (member "--" ccl:*command-line-argument-list* :test #'string=))
  ; ccl --load sleepsort.lisp -- 1 2 2 3
  )

スレッドを作る

 とりあえずBordeaux Threads (←誰か読み方おしえて)を使っておけば処理系ポータブルになるかなーと思って使ってみる。

(dolist (arg (args))
  (bordeaux-threads:make-thread
    (lambda ()
      (sleep (parse-integer arg))
      (format #.*standard-output* "~&~A~%" arg))))

 これで引数全部に対してスレッドが走るようになった。値分だけsleepして出力するスレッド。

スレッドが全部終わったら死にたい

 ここまでで一応ソートはできるのですが、スレッドが全部走り終わってもREPLが起動したままで死んでくれません。カッコ悪いのでスレッドが全部終わったタイミングで(quit)が走るようにしてみました。

(let ((threads (mapcar (lambda (arg)
                         (sleep (parse-integer arg))
                         (format #.*standard-output* "~&~A~%" arg))
                       (args))))
  ;; スレッドが全部終わるのを待つ
  (dolist (thread *threads*)
    (bordeaux-threads:join-thread thread)))

(quit)

Oh god, it works.

Sleep sort実行例

コード全部

(ql:quickload :bordeaux-threads)

(defun args ()
  #+allegro (cdr (system:command-line-arguments))
  ; alisp -#! sleepsort.lisp 1 2 2 3
  #+sbcl (cdr sb-ext:*posix-argv*)
  ; sbcl --load sleepsort.lisp 1 2 2 3
  #+clisp ext:*args*
  ; clisp sleepsort.lisp 1 2 2 3
  #+ecl (cdr (member "--" (si:command-args)) :test #'string=)
  ; ecl -load sleepsort.lisp -- 1 2 2 3
  #+cmu ext:*command-line-application-arguments*
  ; cmucl -load sleepsort.lisp -- 1 2 2 3
  #+ccl (cdr (member "--" ccl:*command-line-argument-list* :test #'string=))
  ; ccl --load sleepsort.lisp -- 1 2 2 3
  )

(let ((threads (mapcar (lambda (arg)
                         (sleep (parse-integer arg))
                         (format #.*standard-output* "~&~A~%" arg))
                       (args))))
  (dolist (thread *threads*)
    (bordeaux-threads:join-thread thread)))

(quit)

 あたかも全部の処理系で動きますみたいなコードですが、CCLでしか確認してません。僕のSBCLはマルチスレッド対応してないんだよね :p

 追記: 他の言語のを見てるとスクリプトじゃなくて関数として書いてる人も多いので関数として実装しなおし。コマンドライン引数から取る必要がなくなったのでparse-integerがなくなる。

(defun sleep-sort (&rest args)
  (let* (result
         (threads (mapcar (lambda (arg)
                            (bordeaux-threads:make-thread
                             (lambda ()
                               (sleep arg)
                               (push arg result))))
                          args)))

    (dolist (thread threads)
      (bordeaux-threads:join-thread thread))

    (nreverse result)))

コンパイル時にsleep sort

そろそろ誰かC++でコンパイル時sleep sortを書いてるはず。

 マクロ書いちゃった><

(defmacro sleep-sort* (&rest args)
  `(list ,@(apply #'sleep-sort args)))

参考サイト

Modern Common Lispはじめました

| 【2分で読めるよ!】 | コメント(2) | トラックバック(1)

 Modern Common Lispというブログをはじめました。僕と、アリエルの同僚で友人の松山さんの2人で交代で更新します。

 第1回は松山さんの、CL処理系についての記事です。


 公開する前に彼は僕に原稿を見せてくれました。そのときの会話を再現します。

 僕と松山さんは普段だいたい英語で会話するので以下英語のままです。カッコでS式、ではなく日本語訳を書いておきます(参考)。

松山「Have you checked the entry? (記事は読んでくれた?)」
深町「Yeah, I already did. (うん、見たよ)」
松山「How about it? (どう?)」
深町「I think, you don’t have to introduce many implementations. If I write the entry, I would write this. “Use Clozure CL. Don’t use SBCL”. (僕はいろんな処理系を紹介する必要はないと思う。もし僕が書くならこう書くね。「Clozure CLを使え。SBCLは使うな」)」
松山「I don’t think SBCL is so bad except the speed of compilation. (僕はSBCLはそれほど悪くないと思うよ。コンパイル速度を除けば)」
深町「It is unstable. (不安定だ)」
松山「Clozure CL is unstable as well. (それならClozure CLも不安定さ)」
深町「I heard that CLSQL doesn’t work well on latest SBCL. (最新のSBCLではCLSQLは動かないそうだしね)」
松山「Anyway, I wrote “We suggest using Clozure CL”. You should be satisfied about it. (まあ「Clozure CLを使うことを勧める」と書いたから、それで満足してくれよ)」
深町「…****!!!!」

 まあ別にSBCLを使うなって気持ちが伝わってくれればどちらでもいいです。


 このModern Common Lispでは、松山さんがCLを書き始めて知った最近のCL事情と、僕がClackを作る上で得た”Modern”な何かについて書いていこうと考えています。

 ここで僕が定義する”Modern” Common Lispは、その読みやすさです。Clackでは読みやすいコードとは何かを真剣に考えています。そしてそのために、今までCLライブラリで当たり前に行われてきた慣例をいくつも破っています。書き終えた今、それは正しかったと確信しています。

 なのでもちろん、このModernの定義は一般的に使われているものではありません。あくまで僕がこれから推進していく上でベストプラクティスとして提案するものと考えてもらったほうがいいでしょう。

 更新は最低で週1回のペースを保とうと思います。興味があればぜひ購読してください。

WEB+DB PRESSの特集「Scala & ClojureではじめるJVM言語」に寄稿しました

| 【2分で読めるよ!】 | トラックバック(0)

CTO「深町さん、Clojureの記事を書きませんか」

 と井上さんに言われたのはもう4ヶ月も前のことです。WEB+DB PRESSの特集「Scala & ClojureではじめるJVM言語」をアリエルで書くことになり、僕にそのClojureの章を担当してもらえないかという話でした。

 その頃僕は、SoftwareDesignで二度、Emacsの記事を書いていてとてもうんざりしていました。そして、「もうLispの原稿以外は書かない」と決めた矢先のことです。

 Clojureと言えばLispじゃないですか。それなら書いてもいいかも…。いや…。

僕「何を書けばいいんですか?」

 ここは慎重になるべきです。

CTO「まだ詳細は決まっていませんが、DSLかWeb系か」

 LispでDSLと言えば……マクロ……!!!

僕「最近ClojureでL5というプレゼンツールを作ったんですが、その話なら」
CTO「じゃあそれでいいです。」

 なんと雑誌でLispの、しかもマクロの記事が書けるなんて思いもしませんでした。さらにL5の宣伝ができるなら原稿を書くのも耐えられるというものです。

僕「どういった視点で書けばいいですか? たとえば、Lispは知っている前提でいいのか、lambdaは知っている前提でいいのか、マクロは知っている前提でいいのか」
@liris「ハードル高っ」

Lispを知らないJavaプログラマ向けでお願いします

 もうこれは絶望です。JavaプログラマにLispを一から、しかもたったの8ページで説明するなんて無謀です。無謀過ぎます。

僕「……さすがに無名関数は知ってる前提で構いませんよね?」
「いや、できれば知らない前提で」


 ……。


いちからか? いちからせつめいしないとだめか?


 Javaプログラマとは言えWEB+DB PRESSを購読しているような人たちが無名関数の存在を知らないとか考えづらいのですが、まあそういう要求であれば仕方がありません。そして必死に考えた末、ひとつの結論に行き着きました。

 僕がLispを始めるきっかけとなった「ハッカーと画家」は、Lispの細々とした話は出てきません。一からLispの文法の説明をしたところでLispの魅力は伝わらない。重要なのは「Lispをやってみたい!」と思わせること。であればPaulのように、ひたすらLispはすごいんだぜという論調で書こう、と。

 なのでClojureの”入門記事”というよりも”紹介記事”と言ったほうがいいかもしれません。


@liris「深町さん、Java嫌いそうですよね」
僕「え、でもdisり要素はいれてないはずですが…」
@liris「行間に漂ってますよ」


 WEB+DB PRESS Vol.61は2月24日に出ます。行間に漂うLisp最強オーラを感じていただければ幸いです。


プロフィール

Name:深町英太郎
Age:歳 (1987〜)
Living:京都府
Hatena Id:id:nitro_idiot
Facebook:eitarow.fukamachi
mixi:ID:6756132
Twitter:nitro_idiot
GitHub:fukamachi
LinkedIn:eitarowfukamachi

最近のコメント

Techonrati

Technorati search

» リンクしているブログ

Powered by Movable Type 4.23-ja