近況
概要
だいたいのプログラミング言語には、REPL(Read-eval-print loop)がある。簡単に言うと、ワンラインで動作を確認できるような対話型コンソールのことだ。Rubyならpryが有名だろうし、PythonならIPythonがある。
そこで、最近はREPLをちょっとだけリッチなシェルとして使ったりしている。もちろん、ちゃんと実行ファイルにして、パスを通せば、シェルで共通的に扱うことが出来るのがわかっているのだけれども、しかし最近はREPLに閉じこもるのもいいものだということで、REPLに寄り添う生活を提案したいというのが、今回の記事になる。
実例: Emacs + Slime
ログバーでは、最近は、開発陣はSlackを使うようになっている。だけど、開発中にSlackの画面に移動してフォーム入力するのは面倒くさいなーと思ったりしていた。どうせなら、普段、開発環境として使っているEmacsから反応出来るようにしたいなーと思ったので、どうせだしSlimeを立ち上げて、Common LispのREPLから、反応を投稿出来るようにしたいなと思ったので、そういう風なコードを書いたりしていた。
Slackに投稿する部分に関しては、各チャット専用のトークンを習得後に、トークンと一緒に該当するAPIに投稿内容を投げればいいので、実装自体は楽だ。自分の場合は、以下のような関数とマクロを定義している。
前のエントリでccl::getenvは、別に置き換えられることを指摘されているので、そこが修正されていないのはご愛嬌いう感じでお願いします。
(defvar *user-token* (ccl::getenv "SLACK_TOKEN")) (setq drakma:*drakma-default-external-format* :utf-8) (defun post-message (channel text token) (handler-case (progn (drakma:http-request "https://slack.com/api/chat.postMessage" :method :post :parameters `(("token" . ,token) ("channel" . ,channel) ("text" . ,text) ("as_user" . "true")))) (error (cond) (declare (ignore cond)) (format t "Connection Error.")))) (defmacro defchannel (channel) (let* ((channel-name channel) (slack-channel (format nil "#~a" channel-name)) (method-name (intern (format nil "~a->" (string-upcase channel-name))))) `(defun ,method-name (&rest texts) (mapcar #'(lambda (text) (post-message ,slack-channel text *user-token*)) texts)))) (defchannel random) (defchannel dev) (defchannel general)
上に関しては、各種関数定義はマクロで抽象化したほうがいいんだろうな、と思って初めてマクロを使ってみたのだけれど、なかなか便利だった。これでdefchannelで各種のチャンネルにポストする関数を自動生成してくれるので、とてもよい(このあたりはこのstackoverflowを参考にした
けど、これが筋がいい方法かは怪しい、みたいなことが何処かに書いてあったような気がする)。
ちょっとポイントとして気になったのは、internを使うと、マクロ上で使える関数名になるっぽいのだけれど、例えば小文字のままだったりすると、|foobar|みたいな、特殊な名前になるので、もし関数名を使うときは、上に書いてあるように、string-upcaseを使って、関数名を大文字に統一してやる必要がある(確か、Common Lispではそういう仕様だった気がする)。こうすることによって、Emacs + Slime上からチャットの反応が出来るので、少し便利だという感じである。
ちなみに、どうせだからということで、Slime上からTwitterに反応できるようにもしている。色々と調べた結果、Chirpが一番使い勝手がよさそうなので、それを使っている。
(defun open-mind () (progn (setq chirp:*oauth-access-secret* "Your access secret") (setq chirp:*oauth-access-token* "Your access token") (setq chirp:*oauth-api-key* "Your API Key") (setq chirp:*oauth-api-secret* "Your API Secret"))) (defun twit-> (txt) (progn (open-mind) (chirp:statuses/update (format nil "~a #+:ccl" txt))))
わざわざ設定部分を分けている理由としては、他にサブアカウントも呟けるようにしているという理由がある。ちなみに、#+:cclみたいに、つぶやきに処理系を入れているのは、とあるCommon Lisperの人が、そういう風につぶやいているのを見てかっこいいなあ、と思ったのでそうしている。
このようにすることによって、Emacs上で、Twitterで愚痴ったり、あるいはチャットに反応出来るようになるので、とても良い。
Ipython Notebook
自分は、元々Pythonista出身なのだけれど、Pythonで良いREPLといえば、IPython Notebookだろう。基本的には対話的に、データを分析したりして、それの過程を共有したりするみたいなことを考えているのかもしれないけれど、とはいえ、REPLの進化としては非常に興味深いところがあると思う。
Telling Technology Stories with IPython Notebook ...
Interactive Music
REPL上でリアルタイムコーディング・ミュージックをするということは、各種で試されている。
例えばHaskellは以下のような感じだ。
上に影響されて、自分も簡単なREPL上で演奏するライブラリを作ったりしていた。
ちなみに、REPL環境とはちょっと違うけど、こういう風にリアルタイムにLEDをピカピカ光らせるデモもあるみたいだ。
the clojure/clodiuno repl with the arduino uno ...
まとめ
確かに、シェル上でコマンドを作って実行する、というのは正当法である一方で、REPLもひとつの環境と捉えて、そこから色々と操作して生活を便利にしたり、楽しいハック環境として使うというのはとてもいいことだと思うので、今後も秘伝のタレを延々と作っていきたいと思ったりした。