やろーじだい

ブログです

Emacs: powerline で eyebrows が表示されない問題と一時的な解決方法

powerline を使っている状態で eyebrowse が表示されないので利用できないのかと思っていたがウィンドウ番号がモードラインに表示されていないだけで起動はしていた。

github.com

この issue にあるように修正する。最新の 20180115.1942 バージョンでは 84 行目になっている。

(funcall separator-right face2 face1)
(funcall separator-right face2 mode-line)
(powerline-raw mode-line-misc-info mode-line 'r)
(funcall separator-right mode-line face1)

上を下のように修正・byte-compile した後 Emacs を再起動することで表示できた。今のところこの修正に関するプルリクなどは出ていない。

追記:以下のような add-advice を用いた方法で直接ファイルを編集する必要が無いことがわかったのでこちらの方が良いかもしれない。

emacs.rubikitch.com

パッケージの方は触らずに一部だけ override する方法があればもっと良いが、とりあえず関数を丸々コピーした。別な関数を使っているだけに見えるが、 powerline 上で powerline-default-theme を呼び出している場合も新しく起動したものを呼び出してくれるはずなのでこうした方が良いと思う。

(defun powerline-default-theme-for-powerline ()
  "Setup the default mode-line."
  (interactive)
  (setq-default mode-line-format
                '("%e"
                  (:eval
                   (let* ((active (powerline-selected-window-active))
                          (mode-line-buffer-id (if active 'mode-line-buffer-id 'mode-line-buffer-id-inactive))
                          (mode-line (if active 'mode-line 'mode-line-inactive))
                          (face0 (if active 'powerline-active0 'powerline-inactive0))
                          (face1 (if active 'powerline-active1 'powerline-inactive1))
                          (face2 (if active 'powerline-active2 'powerline-inactive2))
                          (separator-left (intern (format "powerline-%s-%s"
                                                          (powerline-current-separator)
                                                          (car powerline-default-separator-dir))))
                          (separator-right (intern (format "powerline-%s-%s"
                                                           (powerline-current-separator)
                                                           (cdr powerline-default-separator-dir))))
                          (lhs (list (powerline-raw "%*" face0 'l)
                                     (when powerline-display-buffer-size
                                       (powerline-buffer-size face0 'l))
                                     (when powerline-display-mule-info
                                       (powerline-raw mode-line-mule-info face0 'l))
                                     (powerline-buffer-id `(mode-line-buffer-id ,face0) 'l)
                                     (when (and (boundp 'which-func-mode) which-func-mode)
                                       (powerline-raw which-func-format face0 'l))
                                     (powerline-raw " " face0)
                                     (funcall separator-left face0 face1)
                                     (when (and (boundp 'erc-track-minor-mode) erc-track-minor-mode)
                                       (powerline-raw erc-modified-channels-object face1 'l))
                                     (powerline-major-mode face1 'l)
                                     (powerline-process face1)
                                     (powerline-minor-modes face1 'l)
                                     (powerline-narrow face1 'l)
                                     (powerline-raw " " face1)
                                     (funcall separator-left face1 face2)
                                     (powerline-vc face2 'r)
                                     (when (bound-and-true-p nyan-mode)
                                       (powerline-raw (list (nyan-create)) face2 'l))))
                          (rhs (list (powerline-raw global-mode-string face2 'r)
                                     (funcall separator-right face2 mode-line)
                                     (powerline-raw mode-line-misc-info mode-line 'r)
                                     (funcall separator-right mode-line face1)
                                     (unless window-system
                                       (powerline-raw (char-to-string #xe0a1) face1 'l))
                                     (powerline-raw "%4l" face1 'l)
                                     (powerline-raw ":" face1 'l)
                                     (powerline-raw "%3c" face1 'r)
                                     (funcall separator-right face1 face0)
                                     (powerline-raw " " face0)
                                     (powerline-raw "%6p" face0 'r)
                                     (when powerline-display-hud
                                       (powerline-hud face0 face2))
                                     (powerline-fill face0 0)
                                     )))
                     (concat (powerline-render lhs)
                             (powerline-fill face2 (powerline-width rhs))
                             (powerline-render rhs)))))))

(use-package powerline
  :defer nil
  :init
  (advice-add 'powerline-default-theme :override 'powerline-default-theme-for-powerline)
  (powerline-default-theme))

github.com

github.com

おまけ

eyebrows で新しいウィンドウを作成するときに現在のバッファーをコピーする挙動を期待することは少ないので eyebrowse-create-window-config した時に *scratch* を開くように advice-addしている。

(advice-add 'eyebrowse-create-window-config
            :after (lambda () (switch-to-buffer "*scratch*")))

追記: それ用の設定があった。

github.com

(setq-default eyebrowse-new-workspace t)

2017 年を振り返りながら 2018 年の抱負

カレンダー、ブログ、 Github、メモなどをもとに 2017 年を振り返りながら 2018 年の抱負を考える。

 この記事は修論からの現実逃避のために書かれた。

1 月

プログラミング

大学の授業で Haskell をやりながら Scheme48 を読み実装し、それに合わせて自分なりに考えたことを記録し教科書的に読めるものを作りたいと思った。しかしこれに関しては今読みなおしてみると全然何が言いたいかわからず、そういった文章を書くことの難しさが良くわかった。今は中途半端なところで止まっている。

github.com

読書

この頃から読書メーターに感想を書くことと、何を読んだかを記録することが減っている。夏頃にはオンライン上では完全に読書の記録を取らなくなっている。それによって自分が読みたい本を読みたいタイミングで読むようになったと思うが、一回一回の読書体験が薄くなった気もするので今年は折衷案として書くべきだと思ったものだけ感想を書くようにしたい。読書メーターを知り合いに見られるのはなんとなくはずかしいので公開していない。

2 月

インターン

二泊三日のインターンfronteo に行っていた。朝の満員電車があまりにも辛く、東京で朝の定時出社が必要な会社には絶対に就職しないと決めていた。

 インターンの内容自体は自分の問題であまり良いものにはならなかったが、就職を考えている時に実際に会社で働いている人と長時間話せたのは良かった。この会社ではインターンの後すぐに試しにということで就活をしたが落ちてしまい、それは仕方ないとしても何故落ちたのかというフィードバックが全く無いシステムは本当にしんどいなあと思い一社目にして既に就活が嫌になった。

プログラミング

会津では TensorFlow を使った勉強会などがあったので参加してみたり、 Haskell での Scheme 作成に飽きたりした。試しに行ってみるか程度のモチベーションで勉強会に行くのはよくないということがメモに書き残されていた。

 社会に出てからは、これだと思った勉強会やコミュニティなどがあれば参加してみたりしたい。

3 月

就活

就活二社目として 株式会社NTTデータ数理システム に行ったが数学の筆記テストがほとんどできず足切りすらも越えられないほどの勉強量であったことを自覚した。したはずなのだがイマイチその反省を活かせていない一年だった。今からでもします。

食事

卒業していなくなる同級生といろいろ美味しいものを食べていた。鶴ヶ城近くにある 野菜ビュッフェレストランいわたて- がとても良かった。

プログラミング

Matlab で研究用の拡張 MLP を実装したりした。ベースとなる部分を切り出して公開したりもしていた。

4 月

区切り

2017 年になって初めてブログを書いていた。2016 年に書いていたとりあえずまとめるということについてその後考えたことを書いており、この頃から物事は最後までやらなければならないのではなく、区切りをつけなければならないのではないかというようなことを考えるようになったらしい。多分 日本の思想 を読んだ影響なども大きかったように思う。しかし色々なものが区切りなく自分の中にごちゃごちゃと混在している状態は現在も殆ど改善されていない。それはそこまで悪いことではないのではないかという思想も出てきたのだが、その辺りについても長いこと区切りを付けれていない。

lhcpr.hatenablog.com

改めてブログを読み返してみると自分で書いたことを殆ど覚えていなくてびっくりした。人間は長いスパンでも同じことを考えては忘れてを繰り返しているというのが良くわかる。少しでも次に進むために (同じことを何度も考えないために) 考えたことを書き残して、かつ時間を置いて読み直す機会を設ける必要がある。

Aizu SICP の再開

SICP 読書会を再開していた。 SICP 読書会を通して上で言っているとりあえずまとめるということを実践できていたので、考えて終わりがちな私が具体的なものに対してきちんと実践できていることがわかって良かった。また一応ここでは就活時に自覚した数学力の無さを反省してまじめ数学の部分もやることにした。やってみるととても楽しく、また盛り上ったので勉強会開いて良かったなあと思ったりしていた。

5 月

金沢

結果的に一緒に働くことになった人に会うために金沢に行っていた。寿司が美味しかった。

プログラミング

金沢で会った人と話した結果、 Scheme を使って adviser と言う、作業時間などを通知したり考えがつまった時に用意してあるアドバイスをランダムに表示して疑似的な会話をしている状態にしようという目的でアプリを作ったりした。より会話をしている雰囲気を出すために人工無能など入れてみようかなど考えていたのだが途中で止まっている。

github.com

会話

上のものを作りはじめたのは、会話による影響 (考えがまとまる、間違いに気付くなど) がとても大きいというのを実感することが多かったので、そういった効果を再現できたらおもしろいと思う、というようなことを金沢で話していたのがきっかけだったと思う。しかしそういった会話の影響の研究などをより詳しく調べたりする必要がありそうで、実現されるまでは実際に人と話すしかないなという現状になっている。

emoji

Github で絵文字を使うようになった。 Commit が楽しくなるのでオススメだ。

github.com

6 月

運動

研究室で運動しようということでフリスビーを投げて遊んだりした。将来は大型犬とフリスビーを追いかけまわしたいという夢がある。

イギリス

学会のためイギリスのエクセターに行って観光した。日本から遠すぎるという点以外は良いところだった。

lhcpr.hatenablog.com

プログラミング

Adviser 開発を継続していた。また Smalltalk に入門したりした。 自由自在 Squeak を読んでいる途中であったことを思い出したので、時間が空いた時に再開したい。

7 月

PRML 勉強会

研究室内で PRML 勉強会を主催し、開始した。しかし空き時間は SICP を優先しているので第 10 回で止まっている。演習が楽しいのでちゃんとやりたいと思いつつちゃんとやれてないものの一つになっている。

プログラミング

Adviser の開発を継続中で 7 月には scheme の継続について調べていたりした。

8 月

青森での学会

青森での学会に参加していた。

lhcpr.hatenablog.com

スマブラ wiiU

大学内で仲良くなった人とこの頃から定期的にスマブラwiiUをするようになった。今も月2,3回やっている。

9 月

SICP 合宿

会津芦ノ牧温泉SICP 合宿をした。

lhcpr.hatenablog.com

本屋

東京で良い本屋体験をした。東京に行く時はよく寄っている。

www.title-books.com

 会津でもいろいろと探したが最後まで行きつけの本屋はできなかった。

 会津では毎年「一箱古本市」をやっているので行ってください。

一箱古本市 | Book! Book! AIZU 公式サイト|会津のまちで本に出会う。

10 月

ブログも Github も公開したものがなく何をしていたのか良く覚えていない。

11 月

学会

アメリカのフロリダに行って学会に参加していた。遠かった。ブログなど書いていないことに今気付いた。

プログラミング

11 月から Clojure を再開した。それについては Aizu Advent Calendar で書いた。

lhcpr.hatenablog.com

12 月

やったことリスト

Scrapbox で「やったことリスト」を書くようにした。集中力が無いのでなかなか一つのことが終わらず、今日も一日ほとんど何もやっていないなという自己嫌悪に襲われることが頻繁にあった。しかし、やったことをとりあえず細かく書いていくと毎日様々なことをやっていることがわかり、少し自己肯定感が湧いたので良い取り組みだった。今もほぼ毎日継続できているので続けていきたい。

プログラミング

基本的にレイトレーシングのプログラムを書いていて、研究以外である程度の長時間を一つのプログラミングプロジェクトに使ったのは久しぶりだったので楽しかった。今後もレイトレーシングについての勉強は続けていきたい。

金沢

金沢で今後の事を話したり、部屋を探したり、フリスビーを飛ばしたりした。

総括

2017 年は特に目標もなくダラダラとやってしまった。 2018年は大きい目標はもちろんだが朝の時点での一日単位の細かい目標をおおざっぱにでも設定して、一日単位で目標達成経験を積んでいきたい。いまだに自分の生産性などがわかっていないので、学生の内にもう少し自分の情報を数値化する手法を試しておき社会に出てからも継続していきたい。

 また課題としては、致命的に計画 (計画を立てること・立てた計画を守ること) が苦手なので、計画というものとの付き合い方 (自分でも計画をうまく立てる方法・計画の代替となる何かを見つけること、など) を考えたい。

Clojure-n

すいません遅れました。この記事は Aizu Advent Calendar 2017 向けに書かれました。

 前日は id:mic_psm さんの 部屋を探す話 でした。ヅドベント参加者のみなさんお疲れ様でした。

micpsm.hatenablog.com

はじめに:挨拶

ヅドベント 25 日目を担当します cl_yaho です。大学院では延々と Matlab 書いてました。

 今回書く内容には「はやりのやつ」と書きましたが、はやりといえば Clojure です。心無しかクリスマスと語感が似ている気がします。メリークリスマス!

対象読者

Clojure に興味がある人、最近始めた人など。 この一ヶ月 Clojure を書いていたので、書く時に考えていたことや参考にした記事などをまとめた。

前置き:内容と Lisp について

このアドベントカレンダーに登録した頃に日本で Clojure に関するスピーチ が話題になっていたのではやりということにした。以前行われていた日本の Clojure に関するイベント Clojure/conj 2017 上映会#1 では スピーチを日本語でまとめたスライド が公開されており、これが大きなきっかけとなったようだ。プログラミング言語である Clojure を作成している人間の思想を少し覗くことができる。

 私は Lisp が好きであり、あえて特定のものではなく「Lisp」 が好きというのは、今存在している様々な Lisp と、そしてその Lisp と様々なプログラミング言語を糧にして今後産まれてくるであろう新しい Lisp に対する思いからである。 Lisp の良さの一つはそういった生命体的な存在であることが挙げられると思う。今回はその中でも Clojure について書いていく。

 Clojure は丁度 2 年ほど前に機械学習アルゴリズムを実装してみるなどして少し触っていたのだが、その後の 2 年は研究でもバイトでも Matlab を使っていた。なので久しぶりの再開ということになった。

 Clojure を知らない人の興味をそそるかもしれないおもしろい情報としては、Typed Clojure という、漸近的型付けと呼ばれる技術を使った型システムライブラリがあったり *1 、または Spec という、述語をベースにした検証システムライブラリなどもある。更に ClojureScript という Clojure とほぼ同様に書ける AltJS が存在したりする。 *2 こういった機能がライブラリとして使える (言語基盤として実装されていない) ことが可能であることも Clojure を含む Lisp のおもしろいところだ思う。

 ただし、この一ヶ月 Clojure を書いたり読んだり、それ関連の記事を漁ったりして感じたことは、 Clojure では「複雑な機能は必要になった時に使う」というような思想があるようであるということだ。例えば始めから型システムの恩恵を受けながらプログラミングがしたいと思っているのであればそういう言語を使うべきで、型システムや検証システムを持つ言語として扱われることを Clojure は想定していないように思う。まずはマップを中心としたシーケンス処理で実現する。それで目的が達成可能であればそれでよく、難しい場合に Clojure の上で実現されている様々な機能 (ライブラリ) を利用していく、という姿勢が正しいように思った。間違っているかもしれない。

 前置きが長くなったが今後はひとまず Clojure を使ってやっていきたいと言うことと、就職先で Clojure/ClojureScript を使うことになったということ、さらにこれまであまり手を動かしてこなかったことに対する反省から「Clojure で何か n 個くらい作ろう」と思い立ち Clojure-n プロジェクトを先月下旬に発足した。今回の記事では、先月末からそのプロジェクトの作品ということで作ったものを、作っている時に参照した場所や考えていたことなどを踏まえてまとめたい。

Clojure-n

Clojure-n は n 個のテーマのもと何か物を作りましょうというもので、 n は任意の整数である。

 やる気に満ちていたので今日までに 100 個くらいできている予定だった。しかし力が及ばず公開できるのは 2 つのテーマになってしまった。

Web

初めのテーマはきっかけがあり Web になった。 Clojure どころか Web 上で動くものを作ることが人生でほぼ初めてだったが、今回作ったものは大変な自信作になったので Heroku を利用し公開した。

https://oxtu.herokuapp.com/

ルーティングも実装済みである。

https://oxtu.herokuapp.com/i/

揺れる oxtu に HTML タグを付けて遊べます。

 参考にしたと言ったら怒られそうだが Clojure で Web 開発をはじめてみよう を参考にした。初めて Web をやる人間が躓くであろう概念について説明してくれているのでとてもありがたかった。上のページのコードは Github - iyahoo/oxtu に一応上げたが現在は実験場になってしまっているので Github - iyahoo/oxtu/tree/c07125e25b449432957dc968c これがコミットがほぼ最小の状態になっている。

 また上記の入門記事を書いている方がその続きとなる記事を書いている。 ClojureでWebアプリケーション開発がしたい初心者の方へ 私はそもそも Web における「フレームワーク」というものに全くピンと来ないので、今後作っていくものの中で実際使いながら確かめたい。

レイトレーシング

数年前からレイトレーシングしたいという思いがあったので本を読んで勉強した。23 日に担当していた @yopio_ 君のオススメで 週末レイトレーシング を読んだ。この本では実装言語に C++ を使用しているので、そのコードを Clojure で書き写す形で勉強したのだが、折角 Clojure で書くので以下のことを意識して書き直した。

  • 小さい関数を組み合わせるように書く
  • 可能な限りシーケンスに対する処理の連鎖になるようにする
  • 副作用は必要でなければ基本使わない

このあたりの Clojure を使う上での考え方などについては以下を参考にした。

特に最初の書籍は参考になった。現在 Clojure は version 1.9.0 が出て、この書籍は version 1.3.0 の頃のものなのだが、最近になっていろいろと記事などを漁ってみても大きな間違いなどを指摘していたりするものは特に見つからなかったので内容は全く古くなっていないようだ。現在も入門書として読んで問題ないと思う。また Clojure に興味があり実際始めるかもしれないという人は事前に二番目の記事を読むことをおすすめしたい。

結果

まず結果として、本を一通り読み終えた後に出力できる画像は以下のようなものができる。

f:id:lhcpr:20171225224327p:plain

物体を並べまくったり、

(近いところからの様子を生成した画像をミスって消してしまったので、明日の朝更新します。とりあえずアンチエイリアスしてないものを貼っておきます。)

f:id:lhcpr:20171225235434p:plain

(同日: 更新しました。物体の配置はランダムにしているので上のと違います。)

f:id:lhcpr:20171226010549p:plain

カメラを動かしたりできる。

f:id:lhcpr:20171226000852p:plain

 まだ焦点ぼけの部分を実装していないので、年末のうちに作ってしまいたい。コードは Github - iyahoo/clj-ray-tracing に上げました。

 レイトレーシングでは画像の書き出し部分以外はベクトルを中心とした数学的な演算が殆どなので、副作用を使わないプログラミングがしやすかった。関数型言語使ってみたいけど特に作るもの思いつかないなという人に個人的にオススメの題材に。

 また今回使ったレイトレーシング本の続編が出ている (ただし未訳) ので、やりたくなったら続編も読もうと思う。 In One Weekend

Clojure に関して

プログラムは例えば以下のように C++ から Clojure に書き変えている。

int main() {
    int nx = 200;
    int ny = 100;
    std::cout << "P3\n" << nx << " " << ny << "\n255\n";
    vec3 lower_left_corner(-2.0, -1.0, -1.0);
    vec3 horizontal(4.0, 0.0, 0.0);
    vec3 vertical(0.0, 2.0, 0.0);
    vec3 origin(0.0, 0.0, 0.0);
    hitable *list[2];
    list[0] = new sphere(vec3(0, 0, -1), 0.5);
    list[1] = new sphere(vec3(0, -100.5, -1), 100);
    hitable *world = new hitable_list(list, 2);
    for (int j = ny - 1; j >= 0; j--) {
        for (int i = 0; i < nx; i++) {
            float u = float(i) / float(nx);
            float v = float(j) / float(ny);
            ray r(origin, lower_left_corner + u * horizontal + v * vertical);
            vec3 p = r.point_at_parameter(2.0);
            vec3 col = color(r, world);
            int ir = int(255.99 * col[0]);
            int ig = int(255.99 * col[1]);
            int ib = int(255.99 * col[2]);
            std::cout << ir << " " << ig << " " << ib << "\n";
        }
    }
}
;; 素直にそのまま Clojure に直したもの
(defn header [nx ny]
  (str "P3\n" nx " " ny "\n255\n"))

(defn int-color [f-color]
  (int (* 255.99 f-color)))

(defn body [nx ny]
  (let [lower-left-corner (->Vec3 -2.0 -1.0 -1.0)
        horizontal (->Vec3 4.0 0.0 0.0)
        vertical   (->Vec3 0.0 2.0 0.0)
        origin     (->Vec3 0.0 0.0 0.0)
        sphere1    (->Sphere (->Vec3 0 0 -1) 0.5)
        sphere2    (->Sphere (->Vec3 0 -100.5 -1) 100)
        world      (->Hitable-list (list sphere1 sphere2) 2)]
    (apply str
           (for [j (range (- ny 1) -1 -1)
                 i (range 0 nx)]
             (let [u (/ i (float nx))
                   v (/ j (float ny))
                   r (->Ray origin
                             (plus lower-left-corner (times u horizontal) (times v vertical)))
                   p (point-at-parameter r 2.0)
                   col (color r world)
                   vs (vals col)
                   [ir ig ib] (map int-color vs)]
               (str ir " " ig " " ib "\n"))))))
;; そこから関数を細かく切り出しシーケンス処理の連鎖にしたもの
(defn header [nx ny]
  (str "P3\n" nx " " ny "\n255\n"))

(defn int-color [f-colors]
  (map #(int (* 255.99 %)) f-colors))

(defn make-coordinates
  [nx ny]
  (for [j (range (- ny 1) -1 -1) i (range 0 nx)] [j i]))

(defn coordinates-to-rate [[j i] ny nx]
  [(/ j (float ny)) (/ i (float nx))])

(defn make-ray [[v u] origin lower-left-corner horizontal vertical]
  (->Ray origin (plus lower-left-corner (times u horizontal) (times v vertical))))

(defn make-color [ray world]
  (color ray world))

(defn make-str [[ir ig ib]]
  (str ir " " ig " " ib "\n"))

(defn make-world []
  (let [sphere1 (->Sphere (->Vec3 0 0 -1)      0.5)
        sphere2 (->Sphere (->Vec3 0 -100.5 -1) 100)
        lis     (vector sphere1 sphere2 sphere3 sphere4)]
    (->Hitable-list lis (count lis))))

(defn body [nx ny]
  (let [lower-left-corner (->Vec3 -2.0 -1.0 -1.0)
        horizontal (->Vec3 4.0 0.0 0.0)
        vertical   (->Vec3 0.0 2.0 0.0)
        origin     (->Vec3 0.0 0.0 0.0)
        world      (make-world)
        allprocess #(-> %
                        (coordinates-to-rate ny nx)
                        (make-ray origin lower-left-corner horizontal vertical)
                        (make-color world)
                        vals
                        int-color
                        make-str)]
    (->> (make-coordinates nx ny)
         (map allprocess)
         (apply str))))

 ここで allprocess というのは座標のペア [x y] を受け取り変換していって "r g b\n" という PNM 画像の一行を構成する形に変換する関数ということになる。この様に一つのデータに対する処理としてまとめることで、map のように渡した関数を並列に実行することができる pmap などが使いやすく便利になる。pmap はコア数 +2 の thread を立てるので、関数の処理が短いとオーバーヘッドの方が長くなってしまい早くならないらしい 参考:Understanding Clojure's Map & PMap(source pmap)

 以下はアンチエイリアスというものを導入後 (※上のコードの allprocess の中に重い処理が入る)、allprocess 一回あたりに用する時間が非常に長くなった状態で (map allprocess)(pmap allprocess) に変更した時の処理時間の変化で、それだけで半分以下になった。

;; 400x200 の画像で、 1 ピクセル辺りのレイの数が 100 の画像を作る
in-one-weekend.core> (time (-main 400 200 100))
"Elapsed time: 902399.49433 msecs"
nil
in-one-weekend.core> (time (-main 400 200 100))
"Elapsed time: 434075.507751 msecs"
nil

今回の例では1ピクセルで行われる計算が、他の場所での計算に全く影響を与えない/受けないので、簡単に並列化することができた。このように Clojure にあった書き方をすると簡単に恩恵を受けることができる。また多くの再帰関数はシーケンス処理の連鎖に変換できると考えて良いと思う。今回の場合は、あるデータの処理の結果が次のデータの処理に影響を与えるという場面では以外では再帰を使う必要がなかった。(今回コードでは、反射によっておこる色の変化を実装している color と一番手前でぶつかる物体を見つけるための hitable-listhit)

 Clojure を書いていて疑問に思うこととして、defmulti/defmethod などを利用してディスパッチを利用するべきかどうかの判断がわからないということがある。2年前に作ったプログラムは defmethod などを使いまくって自分の書きたいように書いてしまっていたので、これが原因で遅かった可能性もある ((といっても使っていたのは Clojure 1.7.0 だったのであくまで要因の一つ。あとは pmap の原理を理解せずに適当に使っていたということも原因だと思う)) 今回のプログラムを組んでいる時はレイトレーシングが処理の重いものであると最初から認識していたので、defmethod を使ったディスパッチはあまり行わなかった。しかし行列演算でディスパッチを行わないうまい書き方がおもいつかなかったのでとりあえず使っていて、これが全体でかなり呼び出されているので、ここを修正できると早くなりそうではある。

 上の疑問についてのヒントは Polymorphic performance が参考になった。この検証結果は 2015 年 4 月 (多分 1.7.0 の開発途中) のものであり、確かにマルチメソッドによるディスパッチを利用した関数呼び出しは他と比較すると遅い。しかし拡張のしやすさなどを考えると、この検証結果よりも更に高速化されている可能性が高い現在ならば、頻繁に呼び出す部分以外ではディスパッチを使っても良いのかなあと思えた。*3 しかしどうも defprecord などで宣言したメンバ関数は cider で監視できないなどデバッグがしづらかったりした。

 まだまだ元の C++ のコードに引きずられて関数とデータをうまく分離しきれておらず、コード全体で見るといまいち Clojure らしいコードになっていないのかなあと思う。この辺りは今後書きながら感覚を掴んでいきたい。

今後の Clojure-n

今回のことをベースにすれば様々なことができそうなのでいろいろやっていきたい。ひとまず質を上げるかどうかは気にせず物を作って、質を上げたくなったやつを適宜上げるという方向にしたい。

 ClojureScript が書きたかったので Lifegame を作りここで公開する予定だったが間に合わなかったので今度作って上げる。

終わりに

動くものや目で見て楽しいものを作るということを全くしてこなかったので、今回選んだテーマは楽しくプログラミングできた。そもそも研究以外には言語仕様を学ぶ以上にあまりプログラミングをしてこなかったので、Clojure-n の活動を続けていきたい *4

 12 月はハチャメチャに忙しく、

  • 新天地にアパートを探しに行き、

  • 免許の更新をしに実家に帰り、

  • 大学向けの研究の進捗を作りながら、

  • 修士論文を書きながら、

  • SICP 読書会をやりながら、

  • 御社での仕事へ向けた準備をしながら、

  • バイトで実験をしながらお偉いさんに自分の研究の意義を語り、

  • また別なバイトでは力仕事をしまくりながら、

ヅドベントネタ作りをした。今年 1 月 ~11 月に活動した総量以上にこの 12 月だけで動きまくった気がするので褒められまくりたい。

 以上です。ここまで読んで下さりありがとうございました。良いお年を!

*1:漸近的型付けについては今年のアドベントカレンダーで見かけた 漸進的型付けの未来を考える という記事がわかりやすかった。この記事で説明されているキャストの仕組みは、 Typed Clojure も内部の処理に手を加えることはしないはずなので Clojure にも無いはず。

*2:ClojureScript について、厳密には別なコンパイラとなるためはライブラリではなく Clojure とは別な言語ということになると思うが、様々な Clojure の資産がそのまま利用できるようになっている。 Clojure と ClojureScript の違いは公式で詳しくまとめられている Differences from Clojrue

*3:Clojure の現在のバージョンは 12/08 で 1.9.0 に

*4:n は任意の整数