備忘録 blog

Docker/Machine Learning/Linux

3Dで使われるオイラー角とクォータニオンとは何か?

tl;dr

3次元上の回転について調べたのでまとめる備忘録。

復習: 2次元の場合はどうだったか

2次元座標上で回転をどう定義するか、ということについては、ここでは詳説しない。

  1. 回転行列
  2. オイラー
  3. 複素数

これらの表現が、3次元上ではどうなるのかについて考える。

3次元上の回転行列

回転を表現するだけであれば3x3行列で十分すぎるはずである。9セルあるので、自由度が9であるように思われがちだが、それぞれのベクトルが単位ベクトルであり、直交しているという制約があるので、実質的に自由度は3である。このため、他の表現よりメモリを必要とすることと、無効となる表現が多いというのが欠点としてあげられる。

しばしば回転は、平行移動などと共通に扱いたいとされる。しかし、3x3行列のままでは、原点に対してはどのような3x3行列との積をとっても原点のままになってしまう。平行移動では、アフィン変換になるので、そこで、  {p = (x, y, z)} に対して斉次座標を利用してもう1次元追加した、  {p = (x, y, z, 1)} を考え、これに対する4x4行列による写像を、回転と平行移動を同時に表現できるフォーマットとして利用することがある。このとき、4x4行列の左上の3x3成分だけを回転行列として扱うことができる。

3次元上のオイラー

2次元におけるx,y軸の拡張であるオイラー角は、一般に

{ \displaystyle
(\theta, \phi, \psi)
}

として表現される。

これは、例えばヨー、ピッチ、ロールの3軸としたとき、それらに対して同時にその角度回転する、というわけではない。最初にある軸に対して回転し、その次は、回転した後の向きに対して改めてx,y,z軸を定義し、次の軸で回転し、最後にまた回転後の向きに対して軸を再定義して回転する、という順番で回転したものの合成として表現される。つまり、この回転の順序のやり方によって、最初の回転軸と最後の回転軸が同じになるパターン*1を含めて12パターンのオイラー角を考えることができる。実際は1つの順序(ZYXやYXZの順など)に決め打ちするものが多い。一方で、回転する前の初期状態のxyz軸に対しての回転を行うという流派もあるようだが、ここではそれは考慮しない。

これによって、3次元上の回転は3つの自由度で表現することができるはずである。利点として、何より我々にとってこの表現方法は直感的であるということと、それぞれの軸における回転は何度回ったとしても表現できるので、180°より大きい回転角を表現することも可能であるということが挙げられる。

しかし実際にこの系を用いると、ジンバルロックとよばれる問題が生じる。これは何か。ジンバルと呼ばれる、三次元のジャイロを考えてみよう。最初の状態では、XYZ軸に対応するそれぞれの軸は、どの2つをとっても垂直になるように交わっている。回転によって、軸間の角度がかわると、場合によっては最も外側の軸と、最も内側の軸が水平になってしまうことがある。このとき、2方向にしか動かすことができなくなってしまう*2

回転を実行することと、その回転を書き下すことの間には、本来は両矢印を引くことができて欲しいのだが、その矢印の両方に問題が残っている。それは、ある回転が与えられたとき、その角度をオイラー角で書き下そうとすると、複数の角度の組み合わせが考えられてしまうこと。これについては、角度の値域を固定することで解決することができる。逆に、ある状態に対して、ある回転を実行しようとするときに、状態によっては、先ほどのように2つの軸が同じ向きになってしまうと自由度が2になってしまい、自由度がない向きに直接回転できなくなってしまうことがある。この後者がジンバルロックであり、これは簡単に回避することが難しい。

この性質から、ある2点のあいだの回転を「補間」することが難しくなってしまう。単純に、2点の角度の相加平均をとったとしても、その補間点の前後での角速度が変わってしまったり、

そこで、実は3つの数字で表現するのではなく、4つの数字で表現すれば、仮に2つの数字が従属関係となり、自由度が1つ減ったとしてもなお、3軸の向きの回転を表現できるということが考えられる。これが、次に関係してくる話題となる。

3次元上の複素表現: 四元数

2次元における複素数の拡張であるから、3次元の表現において、実部が1つ、虚部が2つの三元数というものが存在すれば良いのではないか、と直感的に思うだろう。

{ \displaystyle
t = a + bi + cj (a,b,c \in \mathbb{R}, i^{2} = j^{2} = -1)
}

このとき、2つの三元数の積を考えると、この積には  {ij} となる項が含まれるが、それは元の定義には存在しない項である。つまり、この定義では、積について閉じていないことがわかる。そこで、新しい虚数軸として  {k} を導入する。

{ \displaystyle
q = a + bi + cj + dk (a,b,c,d \in \mathbb{R}, i^{2} = j^{2} = k^{2} = ijk = -1)
}

これで定義された  {q}四元数クォータニオン)と呼び、複素数に期待される種々の性質を満たしていることが計算によって示される。 このクォータニオンを利用することの利点は、先ほどのオイラー角のような特異点が存在しないので、なめらかに2点間の回転移動を記述することができる。また回転行列に比べて、演算の回数が減らせるというのも大きな利点だ。行列は先述の通り、自由度に比べて扱うセルの個数が大きいので、和や積など様々な演算で、スカラー同士の積和の演算回数も多くなってしまう。

しかしながら、クォータニオンを利用する際にも欠点は存在し、オイラー角のように270°の回転などを表現することはできず、最短経路での回転として一意に表現されてしまう。また、最大の欠点は、その値をみても、どういう回転の処理に対応するのかよく分からないというところである。

Blender のリグでオイラー角とクォータニオンのどちらを使うべきか

参考文献

qiita.com

www.opengl-tutorial.org

qiita.com

el-ement.com

*1:XZZのように

*2:軸がない方向に回転させるすべがないためである

宇野常寛「ゼロ年代の想像力」から想像する

ここでは、宇野常寛の「ゼロ年代の想像力」を読み、サブカルチャーを中心として年代ごとを表象する作品と人々の志向について考える。その後、10年代の作品について概観する。

1970年代〜1980年代

東浩紀動物化するポストモダン」によれば、この年代以降、経済成長の停滞によって、戦後も連綿と受け継がれていた戦中の総力戦体制が緩み、大きな物語を失うとともにポストモダン的なデータベース化が進んだとされているが、一方で伝統的な学問体系は依然としてツリー型を保っていたため、齟齬が生じているとしている。具体的には80年代は失われた大きな物語を求めて虚構を捏造し、そして90年代ではデータベース的消費が進んでいったと指摘している。

安保闘争の挫折や消費社会の定着により、終わりなき日常へ対する退屈さが増大したのがこの年代である。その消費社会の定着は、熊代亨「融解するオタク・サブカル・ヤンキー ファスト風土適応論」によれば新人類が牽引し、多くの人々はテレビを通して語られるその消費スタイルを受容することで形作られた。当時はまだテレビや新聞といったメディアの影響力が絶大であり、多くの大衆は多かれ少なかれ新人類の影響下にあり、それとは違って地縁的コミュニティに依拠していたヤンキー、また雑誌や即売会等を通してほそぼそと活動を続けていたオタクとの隔絶が大きい時代であったといえる。

1990年代

かつて大きな物語には代替となる存在があった。例えば宗教は世俗化によって科学にとって代わり、従って大学では神学よりも科学が学ばれるようになった。太平洋戦争の終戦も、帝国主義的史観・価値観からアメリカナイズされた消費主義へと権威が交代したに過ぎなかった。しかしバブル崩壊、冷戦終結によって本格的に大きな物語が失われた。この時代台頭してきたオウム真理教はまさに、その失われた大きな物語を麻原に仮託した存在であった。一方でアニメでは新世紀エヴァンゲリオンが大きな注目を集めたが、結局これはひきこもることでの解決、とどのつまり心理主義であった。

そして同時に現れたのがセカイ系という言葉で表象される、自分と彼女という関係性が世界の帰趨に直結している世界観は、世界の危機/この世の終わりと行為への承認の合成であった。愛を貫くことで自らが全肯定されることが、物語の中で半ば当然のように扱われていたのもこの時代である。

心理主義セカイ系も、どちらも自らの殻の中に閉じこもることでの解決を図っているが*1阪神・淡路大震災オウム真理教事件以後の1990年代特有の世紀末感やバブル崩壊後の先の見えない不況感の中で、その考え方が人々の共感を集めたといたら、その通りなのかもしれない。

2000年代

宇野によれば、2000年代ではサヴァイブ系の作品が隆盛を極めたといっても過言ではない。これは仮面ライダーFate S/N、 野ブタ。をプロデュースといった様々な作品でその手法は手を変え品を変え現れてきたが、これは決断主義の現れである。心理主義の反省として、我々は何らかの決断を下さなければならず、バトルロワイヤル的な空間に於いて人々は何らかの決断を迫られ、そこにドラマが生まれる。そのバトルロワイヤル的な空間は、まさに我々が参加を余儀なくされている空間でもある。

そういった00年代作品の集大成として魔法少女まどか☆マギカが2011年に登場したとき、それはまさに00年代を代表する要素を兼ね備えていたといっても過言でない。コミュニケーション不全による意思疎通の不可能性によるすれ違い、巴マミの死という形で容赦なく突きつけられる現実、そしてその現実に対して最終的に鹿目まどかは決断を下すこととなり、セカイは救済される。こうした枠組みは、00年代における決断主義をまさに象徴している。

この決断主義では、私が思うに「Aも良いけどBも良いよね」といった両論併記を曖昧なまま留めておくのではなく、より積極的に、批判を受けることを覚悟で「Bではなく、Aである」と言い切ることが求められているように感じる。そしてそれは価値観の多様化した時代に、大きな物語による裏付けを失ったがゆえに確固たる根拠なく宣言しなければならないがために、より一層勇気を持つ必要があるように感じる。そしてその決断主義的な意思決定が、例えば短期決戦の新卒一括採用な就活で常に求められるようになってきたといえるだろう。そういう意味では、自分が何者であるかを常に決断し続けなければならない時代であるとも言えるだろう。

2010年代

さて2010年代になると、事態は更に混沌としてきた。いわゆる難民系アニメはどれも男性キャラの不在と女性キャラによる箱庭的な世界を傍観者が眺めるスタイルの作品といえよう。物語レスな世界をむしろ積極的に肯定していく様相が伺えるが、私にはそれが、現実社会におけるコミュニケーションの代償としての濃密な、完成された空間がそれぞれ島宇宙的に世界中に散らばっているようなイメージに見える。

新海誠は2010年代を代表する映画監督の1人だが、特に秒速5センチメートルを観てみると、最後に第三話で、今迄連綿と続いてきたストーリーは断片的描写の集合に回収され、そして突如山崎まさよしone more time, one more chance のPVとなる。そしてその間には、主人公の空白を埋める説明もストーリーもない。彼の映画は物語というよりポエムであり、その独特な語り口に惹かれるところは非常に多いのだが、むしろそのストーリーがないことによって、東の言葉を借りるならばデータベースの要素として主人公の恋愛を分解することによって、自らの経験との何らかの共通項を見いだし、それが自分の心に刺さるようにできている。物語が抽象化されることによって主人公の恋愛は自分の恋愛に射影され、そして何らかの共感ができるようになるのだ。

一方で彼の描く小説は感情表現豊かで、映画では描かれないストーリーの補完がみられる。これは映画とは好対照であり、ある意味で小説と映画が対になることで作品世界を構築しているといえよう。しかしこのようにしてストーリーを付与された登場人物は、ともすれば平板で、二次創作を行う余地(シミュラークル)を失った存在に見えてしまうことも少なくない。

ところで、人々の消費志向も大きく変化してきている。若者のテレビ離れが叫ばれるようになり、インターネットを介した様々な趣味分野における小さなコミュニティに再編されているように感じる。そしてそのたくさんのコミュニティが島宇宙を形成しているというのが現状に対する一つの説明となりうるだろう。先述の熊代の議論を援用するが、この過程の中で従来のオタク/サブカル/ヤンキーといった境界が融解し、かつてのヤンキーは一部の田舎を除いて絶滅し、マイルドヤンキー的な価値観に取って代わった。それによって、ブランド物を消費することを是としていた新人類に憧れを抱いていた中流層は、長いデフレと所得減少によってブランドには拘っていられなくなり、そしてオタクもアニメ、マンガ文化が大衆に知れ渡ったことでライトオタクなるライト層を多く生み出すこととなった。そしてその三極のライト層の中間が重なり合った部分が、現在の general public の姿ではないだろうか。

彼らの消費形態は、ブランドの最先端を行く者、オタクの最先端を行く者が選んだモノ/作品を受容することで成り立っている。従って彼らは審美眼を磨くことをせず、ただインターネット上の評判などを頼りに観る作品を選んでいる。それゆえに、作品の本質的な面白さと作品の売上や注目度が必ずしも一致しないことが少なくない。もしそうだとするならば、本質的にはテレビを観て、そのテレビで描かれているものを無条件に受け入れていた時代の人々と大差ないのではなかろうか。

とはいえ、インターネットのおかげでそのチャネルは当時に比べていくぶんか選択肢が広く、そのために彼らは選択の自由を享受しているかのように錯覚してしまう。そしてそのことに自覚的になったとき我々は消費主義の無力さを悟り、大きな物語からの脱物語と呼応するかのように消費という軛から逃れる脱消費主義的無行動主義に走るのではないか。そしてその萌芽は、20代を中心とする若者の一部で既に見られ始めているのではないかと感じる。

1990年代以降、物語への回帰と脱物語が振り子のように揺れているように感じる。そして10年代は脱物語の年代であった。果たして我々が迎える20年代はどのような作品が展開されるのか、興味深い。

*1:実際にはそれで解決するのは本当にごく身近な問題だけで、世の中の問題は往々にして解決しない

RailsとReactを統合する方法を考える

なぜReactを導入したくなるか

現代のWebアプリケーションの発ではしばしば、リッチなユーザエクスペリエンスを提供するためなど様々な理由で、クライアント側に(ウェブブラウザ上に)状態を持っておきたいという状況があります。例えばチェックボックスにチェックが入っているかどうかで、他のDOM要素の内容が変わったり、モーダルが閉じているか開いているかを管理したり、などなど……。もちろん技術選択として、こうした操作が全く必要ない実装にすることも可能です。しかし、ボタンをトグルしたら画面上に何らかの変化があることをユーザが期待するというように、今やユーザビリティと、動的なウェブページは密接な関連があります。

さてこのとき、ユーザーの操作に応じて、HTMLの階層構造に含まれる1つ1つのタグで囲まれる要素を追加、削除、変更などする必要があります。こうした構造のことをDOM(Document Object Model)と呼びますが、クライアント側でDOMを操作するために、JavaScriptを書くことが事実上不可避となります。しかしながら素のJavaScriptを書くのはウェブブラウザ間の互換性の観点から、かなり大変です。例えば、このような場合に困りました。

event.target.matches('.heart')

これは、選択したDOM要素が、heartクラスかどうかを判定したいコードです。

developer.mozilla.org

これは、IEでは動作しません。なぜならばIEでは、matchesは非標準の名前 msMatchesSelectorというAPIで実装されているからです。またIEでなくとも、FirefoxChromeの古いバージョンのブラウザを利用しているユーザがいれば、このコードを正しく解釈できないかもしれません。これに対処するためには、古いバージョンのブラウザでも動作するように、互換性に配慮した関数定義に上書きするコードを導入する必要があります。これをpolyfillと呼びます。上記の例では、以下のコードがそれに対応します。

if (!Element.prototype.matches) {
    Element.prototype.matches = 
        Element.prototype.matchesSelector || 
        Element.prototype.mozMatchesSelector ||
        Element.prototype.msMatchesSelector || 
        Element.prototype.oMatchesSelector || 
        Element.prototype.webkitMatchesSelector ||
        function(s) {
            var matches = (this.document || this.ownerDocument).querySelectorAll(s),
                i = matches.length;
            while (--i >= 0 && matches.item(i) !== this) {}
            return i > -1;            
        };
}

しかし、JavaScriptで利用したい関数の全てに対してpolyfillを書くのは現実的には不可能です。こうした理由を含めて様々な理由から、クライアントサイドでJavaScriptを書く際にはjQueryと呼ばれる、ブラウザ間の差異を吸収し、様々な使いやすい関数を追加したライブラリが今まで広く用いられてきました。

ところが、たとえjQueryを利用したとしても、実装が困難な場合があります。例えば、

リモートサーバに置いてあるテーブルデータをajaxで取得する間は、テーブルをhiddenにしておくが、ロードが終了したらvisibleにする。けれども途中でロードを止めるボタンをクリックした場合は、その代わりに「ロードを止めた」という旨を表示する

という処理をしたいとします。このとき、ロードを止めたにもかかわらず、ajaxの結果が返ってきたコールバックが発火してしまうと、テーブルが表示され、かつ「ロードを止めた」旨も表示されるということになるかもしれません。このように、本質的に複雑な条件分岐を持つような場合には、とたんにバグ無く条件分岐を全てカバーするのが困難になります。言い換えると、操作AとBがあるとき、A→Bの順で行う操作と、B→Aの順で操作が行われるとき、その操作が冪等になってほしい時には冪等になり、条件付きの場合はその条件をどこか一箇所で管理したいという希望があるでしょう。

これが難しい理由は、jQueryで実装しようとすると、本質的に「現在描画されているDOMの情報を参照して、次のDOMを書き換える」という処理を行うことになるためです。しかし、描画に必要な情報が全てDOMとしてhtml上に現れてきているかというと、実際は必ずしもそうではないはずです。また、仮にDOM構造に現れていたとしても、それらの情報が散らばっていると、それを集めるのは依然として困難です。例えば検索ツールで、様々な検索フィルタを既に選択しているかどうかで取り消しボタンが表示されるか変わるといったことを考えると、それらの全てのフィルタに対して、DOM上で選択されているかどうかの条件分岐を書くよりも、内部に「選択したかどうか」という隠れ状態があって、その隠れ状態から今のDOMが構成されていると考えた上で、その隠れ状態で条件分岐を書く方が自然です。

そこで、クライアントの状態をstateとして持ち、そのstateに応じてレンダリングされるページが決まるとしたら、どうでしょうか。これはある意味ではMVCモデルで、Modelに状態を持ち、Viewがmodelの内容に応じて描画されるというのに似ていますが、Viewの内部にも仮想的に状態を持っており、その状態に応じてページをレンダリングするという機構を考えます。このとき、stateが変更されたときに自動的に必要となる部分の再レンダリングが行われるとします。そのとき、stateに対するビューの実装と、どのコールバックによってstateが変化するかという2点のみを私たちは考えればよくなります*1

このようなことが可能になるのがReactの利点の一つで、他のJavaScriptの類似のライブラリに比べて、JavaScriptとHTMLのDOMが密に連携した書き方ができるので、データフローの見通しが良くなり、モジュール化することも容易になります。そこで、Reactをクライアント描画のライブラリとして選択することにした、とします。

RailsとReactをどう統合するか

私の知る限り、ReactとRuby on Railsを統合するための方法は、おおざっぱに3つに分けられます。

1. Railsのsprocketsで管理する

いにしえのRailsでは*2JavaScriptcssや画像と共にsprokectsと呼ばれるアセットパイプラインで管理されていました。言い換えると、Railsの管理のもとでJavaScriptのコードを書くというスタイルです*3。この場合、JavaScriptのライブラリはnpmで導入するのではなく、著名なライブラリはrubyのgemとして頒布されており、それをRailsに組み込むという形で利用していました。

しかしReactを利用しようとなると、React上で実装されているawesomeなコンポーネントを利用したくなることが多くなると思います。こうしたライブラリはRubyの世界ではなく、JavaScriptの世界、つまりnpmのパッケージとして頒布されているものがほとんどですが、こうしたときに、npmで管理されているライブラリを自由に導入するのに困難があると考えられるので、javascriptのコードはモダンなビルド環境(webpackとnpm/yarn)の上で書きたくなります。

2. RailsAPIサーバとし、ReactはクライアントWebアプリとして個別に実装する。

サーバとクライアントを独立して実装するのは、特にプロトタイピングの場面では少し難しいことがあります。それは、アジャイル開発の過程で頻繁にAPIが書き換わるので、その変更に応じてクライアントとサーバを同時に書き換えないと不整合を起こすことがあるためです。特にこれはRESTのようなルーティングが分かれてカッチリしたAPIを設計しようとすると、この問題は強くなります。設計変更によるオーバーヘッドが大きくなってしまう一方で、開発初期から理想的な設計を常にできるとは限らないので、APIを切り替えるという手間が生じると、その分だけ開発速度が下がってしまいます*4

また特に、Webアプリケーションには、車輪の再発明が必要となる場面が多くあります。例えば、ユーザのセッション管理が必要だったり、CSRFトークンの受け渡しが必要だったり、ルーティングが必要だったりします。これらは、Railsのデフォルトの機能を使えば悩まなくてすむのに、自前で実装しようとするとバグを誘発してしまったり、実装がそもそも大変だったりしてしまうでしょう。ルーティングを含めたクライアントの実装を、全てJavaScriptの世界で完結させるならばそれでも良いですが、Railsのレールから外れることによる再実装のデメリットを甘んじて受け入れたくないというときは多いと考えられます*5

3. Rails上にReactを組み込み、rubyのパッケージ管理とjsのパッケージ管理を共存させる

そこで、Railsのassets pipelineと、webpackで管理されるReactのコードを共存するという方法が、三つ目に考えられます。この方法を利用すると、webpackでJavaScriptのライブラリを自由に導入できるという利点を残しながら、Rails Wayに則って開発を進めることができます*6

github.com

Reactにおける ReactDOM.render(element, container); が、ビューの内部で呼ぶことのできる react_component(ComponentName, Props, Options)というヘルパー関数に対応します。Railsのビューをエントリーポイントとしてpropsを渡すと、以後はReactの世界でコンポーネントを描画できるという形になっています。

まとめ

もちろんここで紹介した方法がベストとは限りません。動的なページが必要かどうかというところから疑うことも時には必要でしょう。RailsとReactの共存は、サービスの規模や開発者のリソースなどによって、取るべき選択肢は変わりますので、長所と短所を検討しながら、ベストな選択をしていくことが望ましいと考えられます。

参考文献

blog.toshimaru.net

*1:もちろんstateが複雑な入れ子になり、その更新が条件分岐を持つものになるように複雑になる場合は、Reduxのようによりデータフローを意識したライブラリを導入することが必要だと考えられます

*2:今もデフォルトではそうですが

*3:javascriptというより、CoffeeScriptとよばれる、alt-JSの一種を利用することが多かったです

*4:昨今ではGraphQLとよばれる、単一のエンドポイントでリソースの問い合わせが行えるようなクエリ言語が登場し、APIの設計をある程度柔軟にできるため問題を緩和してくれる可能性はありますが、まだライブラリ等は少なく、簡単に利用可能であるかというとわかりません

*5:例えば既にstaticに作ったサイトを改修するために、Reactで再実装するのは、限られたリソースの中では大変です

*6:もちろんその欠点として、RailsとReactが密結合になってしまうことによる弊害は様々あります

MacのNotes.appで過って削除されたメモを復元する

tl;dr

Notes.appを使っているとき、sqlite3の書き込みがエラーになったようで、クラウド上への同期もとっていなかったことでNotes.appのメモがあらかた消えてしまった。サルベージを試みた記録を遺しておく。

f:id:sharply:20180319132936p:plain

What I have done

元のファイルのありかを特定しようとする

~/Library/Containers/com.apple.Notes/Data/Library/CoreData/ExternalRecords/NotesV4/{UUID}/ICNote/_records/{[0-9]+}に拡張子がnotesexternalrecordの謎のファイルが大量に残っているが、このファイルはあくまでSpotlightで検索するときに、メモに対して貼っているエイリアスのようなものであるために、そこに実体が残っているというわけではない。実際にファイルサイズは0byteであった。

sqliteの素のファイルを復元しようとする

~/Library/Group Containers/group.com.apple.notes/NoteStore.sqliteNoteStore.sqlite-shmNoteStore.sqlite-walが、また~/Library/Containers/com.apple.Notes/Data/Library/NotesNoteV4.sqliteNoteV4.sqlite-shmNoteV4.sqlite-walがあった。

NoteStore.sqliteに書き込みが失敗し、新しいファイルで上書きされてしまっているようだった。NoteStore.sqlite-walは数MBあるため、もしかしたらデータが残っているのではないかという期待があったが、stringsしてバイナリを見る限りでは、メモの中身が見えるというわけではなかった。

ダメ元でsqlite3でこのデータベースに接続してみることで、ジャーナリングをリカバーしてくれるのではないかと考えたが、sqlite3 NoteStore.sqlite vaccum;といったコマンドを叩いたところで、.sqlite-shm.sqlite-walファイルが消えるのは確認できたが、.sqliteファイルのサイズが変わらず、ジャーナリングはそのまま失われたような挙動にみえた。

このことは、もとの.sqliteファイルが消されてしまったので、Notes.appを起動したときに新しい.sqliteファイルが作られて上書きされてしまったので、リカバリが実行できなかったのではないかというのが1つと、そもそもNotes.appでは、sqlite3の書き込みにログ先行書き込みを使っているようだが(Write-Ahead Logging)、ログ先行書き込みではログを書き出していることによってアンドゥ、リドゥができるので、実際の差分を.sqlite-walファイルに書き出すことをしているわけではないと考えられる。これらのことから、.sqlite-walには実体が入っていないと思われる。

そこでsqliteファイルをリカバリして、Note.appのもとのメモを完璧な形で復元するということは諦めた。

キャッシュを探す

Spotlightで検索したとき、消えたはずのメモが検索結果に出ることから、どこかにテキスト情報としてキャッシュされているのではないかと考えた。そこで、Spotlightのキャッシュファイルのディレクトリから、メモの内容に一致するファイルを抜き出すことを考えた。

# cd /.Spotlight-V100/Store-V2/{UUID}/Cache/
# tree

ここに、文字としてキャッシュされたファイルが保存されている。 このまま普通に全文検索してしまうと、保存されているPDFなどの関係ないテキストデータが大量にひっかかってしまう。そこで、Markdownのように箇条書きで*を列挙していくと、に変換してくれるというNotes.appの挙動を利用して、文字としてを検索するということにした。

# find . -type f -print | xargs grep • | less -S

これを使って、が含まれるメモについてはある程度復元することができた。そうでないメモについては、頑張ってどんな内容が含まれていたのかを頑張って思い出して、ユニークそうな単語を検索することで発見するという操作を繰り返した。

Conclusion

iCloudなどと連携して、オンラインにバックアップを常にとっておくようにしよう。

ガベージコレクション(GC)

tl;dr

ガベージコレクションGC)についてサーベイしたので、メモを残す。

ガベージコレクションのアルゴリズムと実装

ガベージコレクションのアルゴリズムと実装

本文中の多くの記述は、上記の書籍を参考にした。筆者は素人なので、詳細な記述や実装については参考文献を参照されたい。

Introduction

プログラムを書く上では、例えば入力長が分からない入力を受け取るためなどでメモリを動的に確保したい場合がある。その際ヒープ領域とよばれる領域にメモリを確保するが、使い終わった際には解放しなければ、確保しているが使われない領域が生じるメモリリークが発生してしまう。

しかし一般に、その解放を手動で管理することは面倒である。プログラマがどの時点で確保した領域が不要となるか、その全てのオブジェクトに対して追跡することは厄介である。そのために言語処理系やライブラリでメモリ解放の手間を肩代わりするような機能が実装されている。これがガベージコレクションである。

確保したメモリ領域を手動でfreeする場合に比べて、ガベコレのある言語を用いると実装が楽になる一方、GCが起きる条件を制御できず、また多くの実装で無視できない停止時間が存在するといった問題点はあるが、小さいオブジェクトが大量に死ぬような場合ではある種のGCのほうが有利であり、どちらを選択するのが良いかは時と場合による。

GCの評価基準

スループット(単位時間当たりの処理能力)とレイテンシ(要は最大で停止している時間)はトレードオフにあり、GCの種類によりどちらにより重きを置くかは変わる。またヒープの使用効率を向上させる(例えばコピーGCで、断片化を防ぐために生存しているオブジェクトをつめるような実装がある)ことが必要となる場合もある。

C, C++では

Cでは基本的にはGCはない。mallocしたヒープ領域は自分でfreeしなければならない。 C++でもnewした領域はdeleteしなければならないが、スマートポインタというものがあり、boostに実装されているほかC++11では以下のものがある。スマートポインタは、確保したメモリ空間を、スコープから外れたときに自動で開放してくれるポインタである。

  • unique_ptr, shared_ptr, weak_ptr unique_ptrはメモリの所有権をそこに限定するもの。shared_ptrは所有権を参照カウンタによって管理し、共有することが可能である。

参照カウンタ

そのポインタを参照するごとにカウンタをインクリメントしていき、参照しなくなるとデクリメントする。カウンタが0になるとそのカウンタはどこからも参照されないということになり、安全に回収することができる。

このときの問題点として、循環的にオブジェクトを参照したいときにshared_ptrでは、その領域が解放されなくなってしまう。これを防ぐためにweak_ptrが用いられる。弱い参照と呼ばれるが、これは所有権を持たずにメモリを参照できるポインタである。例えば木構造で親子の双方向にポインタを持ちたい場合などに、これを用いることが可能である。

その他、利点として最大停止時間が短いこと、ポインタを走査するという手順が必要ないこと、逆に欠点としてカウンタの処理や実装が煩雑となることがあげられる。

またC/C++上でGCを実装したライブラリもある。

  • Boehm-GC

スマートポインタでなくともmallocのかわりの関数を呼ぶと、自動でfreeしてくれるGCは古くから提案されている。このときGCする対象となるオブジェクトを知りたいが、どのオブジェクトが参照されているかを知るためには、そのオブジェクトをさすポインタがあるかどうかで区別するしかない。しかしながら、入っている値が単なる数値なのかポインタなどのかは区別することができないので、全ての値をポインタと見なしてオブジェクトを辿り、辿れないオブジェクトをゴミとして回収する。このような仕組みで動くGCを保守的GCと呼ぶ。

従って、もしスタックに載った値がたまたまオブジェクトを指すポインタになってしまうような場合は、そのポインタの先がゴミであっても回収されず、データセットによっては大きいスペースリークが発生してしまうことが考えられる。32bitのマシンでは、このようなコリジョンが発生してしまうことは可能性としてそれほど低くないが、64bitのマシンでは場合にもよるが無視できるレベルだろう。

APGAS型の並列計算言語であるX10も、C++にトランスパイルした場合はこのGCによってヒープは管理される。

sharply.hatenablog.com

少し注意しなければならないというか、当たり前のことであるが、参照を外さないとGCで回収されない。逆に言えば参照が外れてしまうとGCで回収されてしまう可能性がある。例えば双方向連結リストでメモリ空間を節約するために、左右のポインタのxorを持っておくという方法があるが、そのような方法で管理しているポインタはこうしたGCでは辿ることができないので、オブジェクトが破棄されてしまうおそれがある。

Haskell

コピーGCをベースに、Cheneyのアルゴリズムや世代別GCを取り入れている。以下のスライドをもとに詳説を試みる。

CS240h Lecture slides

https://takenobu-hs.github.io/downloads/haskell_ghc_illustrated.pdf

Haskellでは、RTS(Runtime-System)がネイティブスレッドやGCについて司る。

コピーGC

生きているオブジェクトを別領域に全てコピーし、もとの領域を全て解放するようなGC

  • Stop the World
    • 実行系は全て停まってガベコレのスレッドだけが動く

コピーGCはゴミを捨てるのにほとんどコストがかからないために生きているオブジェクトが少ないほど有利であり、また別領域に詰め込むことでヒープのフラグメンテーションが起きないことが利点である。そして、GCの途中で参照関係にあるオブジェクトが近接するようになるので、GCに有利である。

デメリットとしては、ヒープ領域の使用効率が悪化すること、保守的GCとの相性が悪いことがある。これは、コピーGCでヒープの値のアドレスが変わってしまうと、それをさすアドレスも書き換えなければならないが、保守的GCをしたいような場合には、スタックなどに積まれている値がアドレスであるか値であるか分からないため、書き換えられるか分からないということがあるためである。

世代別GC

少しの長生きしたオブジェクトは長生きするが、残りのオブジェクトは量が多く、すぐ破棄されるという経験的な性質をもとに、アロケートされたオブジェクトは第一世代に属し、Haskellの場合では生きているオブジェクトが少ないときに有利なコピーGCで回収し、ある程度長生きしたオブジェクトは第二世代に移行し、一般にはそこでは回収しないか、低頻度でコピーGCやMark & Sweepで回収するという仕組みである。

これを組み合わせ世代別コピーGCは、JVMの実装でもみられるが、全く書き換えられないオブジェクトが何度もコピーされるのを防ぐことができる。ここでは高頻度でガベコレされる領域Nurseryと、長生きする領域Generation0, step1とGeneration1を分ける。Nurseryは高頻度にガベコレされる(Minor GC)が、一定以上長生きしたオブジェクトはstep1に移行し、Generation1へと昇格し、それほど高頻度にガベコレされなくなる(Major GC)。

ところで、JVMでもこうしたフィーチャーは実装されているが、Javaのような言語ではthisがあるせいで、Generation1に相当するオブジェクトがNurseryへのポインタを持つことがしばしば起こる。このとき、Nurseryを注意深くガベコレしなければSeg4が起こるため、Nurseryの高速なガベコレを妨げる。これに対してHaskellではmutationがrareであること、またIORefで触るような場合はどのみち遅いことから、一般の場合でそれによるオーバーヘッドはそれほど大きくならない。

また更にmajor GCにおいてはParallel GCが可能である。これはGCのスレッドが複数あり、そのそれぞれがコピーGCを行うが、複数のスレッドが同じオブジェクトをコピーしようとすることがある。しかしそうであったととしても、immutableな小さいオブジェクトであるならば複数コピーされることによるオーバーヘッドはそれほど大きくないため、ロックせずにガベコレを並列で走らせることができる。これで純粋関数であることで柔軟さを得ることが可能となる。

このように、ハイスループットGCHaskellRTSでは実現している。

Go

Go1.5〜でのGCはレイテンシの短縮にフォーカスしている。

Mark & Sweep

  • Mark
    • ポインタを辿り、オブジェクトにマークする
  • Sweep
    • マークが付けられていないオブジェクトは捨てて良い

しかしこの場合、GC実行中にプログラムが動作してポイントの様態が変化してしまうと、本来捨てるべきでない領域をSweepしてしまうかもしれない。こういった問題を防ぐために、一般にはSTWで実行系は全て停まってガベコレのスレッドだけが動くようにしている。しかし当然、STWの間は実行系が動けず、そのレイテンシはヒープ使用量が大きいほど増大することが見込まれる。

また一般に、Mark & Sweepの特性として、以下のものがある。

  • 保守的GCとの相性が良い
  • CopyGCに比べて、フラグメンテーションが起きやすい。また開放されたメモリ空間も非連続になりがち。

Go1.5〜では、Tri-color markingとよばれるオブジェクトを3分類し、コンカレントGCでほとんどSTWを起こさずにGCすることが可能となっている。これはインクリメンタルGCの一種である。

Rust

Rustでは生存時間が型レベルで管理されており、生ポインタを触ることは一般に忌避される。そこで何らかの型でラッピングしてポインタにアクセスする必要がある。

postd.cc

qiita.com

qiita.com

Rustではヒープ領域を確保する方法はBox, Rc, Arcがある。Boxはunique_ptrに対応するようなもの、Rc、Arcはshared_ptrに対応するようなものだと認識している。例えば再帰的データ構造を定義する際、Haskellではそれが参照であることを明示する必要はないが、RustではBoxで明示的にヒープを確保していることを示す必要がある。またRcとArcの違いは、それがスレッド間で共有されるかどうかという点である。

ところが、BoxやRcで指す先の値をmutableにしたいという要請がある。これを一般化するとimmutableなオブジェクトの内部に、mutableなオブジェクトを持つ要請であり、こうした要請に対してRefCell、Cellが用いられる。Cellは単純な型ぐらいに対してしか使えないので、参照型を持つ場合ではRefCellを使うことが多く、Rcと組み合わせてRc<RefCell<T>>のようになる。更に更に、スレッド間でmutableなオブジェクトを共有したい場合はMutexを用い、Arcと組み合わせてArc<Mutex<T>>のようになる。

困ること

ところで、こうした参照カウント方式ではDAGならともかく、循環リストや双方向連結リストのようなグラフ構造を持つことができない。

agtn.hatenablog.com

qnighy.hatenablog.com

これに対してTyped Arenaという方法があるが、領域を開放するためのインターフェースとして実装されているのは、全て捨てるということしかできない。つまり参照しなくなったオブジェクトがArena内にあったとしてもそれをガベコレすることができない。参照しなくなる要素が増える場合、メモリリークが大量に発生することになってしまう。

doc.rust-lang.org

これに対応する方法としては2つであり、1つはfreeListを作り、そこに削除した要素を登録し、次にnewする際にその要素を用いるようにする。ただしその場合は削除した要素が飛び飛びになっている場合、近接して確保したい領域が離れて確保される懸念がある。もう1つの方法としてはある程度使われない要素が増えた時にもう1つArena領域を取り、参照されている要素を走査し詰め込んだ後、元のArenaを全て捨てるというさながらコピーGCのような実装をするかである。

どちらにしてもTyped ArenaはArena内部に持つ要素の型と生存時間が管理されることは利点であるが、参照しなくなった領域に対するメモリリークに対する解決策ではないように思われる。

その他調べたこと

  • RubyはMRubyではマーク&スイープ、Ruby2.1からは世代別GCを取り入れている。
  • Pythonは参照カウントで管理。循環参照GCは世代別GCで管理している。
  • JavascriptのV8は世代別GCで、マイナーGCはコピーGC、メジャーGCはマーク&スイープGC

まとめ

きわめておおざっぱな分類は以下。

言語 種類 特徴 詳細
C 基本的にはなし Malloc, freeで管理
C++11 参照カウンタ unique_ptr, shared_ptr, weak
C,C++(Boehm-GC) Mark & Sweep 保守的GC,STW ライブラリを導入
X10 Mark & Sweep 保守的GC,STW C++にトランスパイルするとBoehmGCが使われる
Haskell コピーGC STW Cheneyのアルゴリズム+世代別GCなど
Go1.4 Mark & Sweep parallel STW
Go1.5〜 Mark & Sweep Concurrent/Incremental
Rust 参照カウンタ 生存時間で管理 Rc, Arc, Arena

参考

www.slideshare.net

GolangのGCを追う | SOTA

postd.cc

dic.nicovideo.jp

qiita.com

zonomasa.hatenablog.com

世代別ガベージコレクション - Wikipedia

seesaawiki.jp

http://matsu-www.is.titech.ac.jp/~endo/gc/gc.pdf

Mostly-Concurrent Mark & Sweep GC のアルゴリズム

qiita.com

dev.classmethod.jp

UEFI環境下でのgrubでLinuxとWindows 10をデュアルブートする

Windowsでのブートの制約

Dual boot with Windows - ArchWiki

上記より、Windows 10ではUEFI-GPTあるいはBIOS-MBRの組合せでしかブート出来ません。ところで旧来のBIOSブートに比べてUEFIブートは高速であることが知られています。またMBRに比べてGPTでは基本パーティション数の制限が緩和されているというように、UEFI-GPTブートがモダンなブート環境であることは間違いないでしょう。特にWindows 10をクリーンインストールするとき、デフォルトでパーティションを切ろうとするとEFI System Partition (ESP) を作る挙動がみられるように、UEFI-GPTでのブートを推奨しているようです。

ここでは、もともとLinuxを起動する際に用いていた従来のBIOS-MBR型で定義されていたgrubのブートをUEFIブートにリフトし、Windows 10とのデュアルブート環境を構築することを目論みます。grub2.02 rc2を用いました。

予めWindows 10の高速スタートアップ機能は無効にしておきましょう。

grub2の仕様

デュアルブート対象のLinux上で作業します。まずは既存のgrubから、UEFIWindowsをチェインして呼び出すことを考えます。そのためにはUEFIWindowsを認識させなければなりません。しかしos-proberを行っても、Windows Boot Managerを発見できません。そこでwikiを参照して/etc/grub.d/40_customに書き込んで、grub-mkconfigしました。

GRUB - ArchWiki

# grub-mkconfig -o /boot/grub/grub.cfg

こうしてgrubのエントリを追加すればもうWindows 10を起動できるようになったのかというとそうではなく、grubのメニューから追加したエントリを選択するとInvalid signatureと言って怒られます。これはBIOS型のgrubからUEFIブートローダーをチェインして起動することが出来ないためであると考えられます。

後で試してわかるのですが、LinuxBIOSブートで起動している場合はUEFIブートのOSを検出してくれませんが、UEFIブートで起動した場合はos-proberWindows Boot Managerを検出でき、systemd-bootやrEFIndと同様にgrub-mkconfigで自動でUEFIWindowsを探してくれます。そこで上記の手順を省略し、下記の方法でUEFIブートによって起動してからgrub-mkconfigを行えば、手動でWindowsのエントリを追加する必要はないと考えられます。

そこで次に、UEFIモードでgrubをインストールすることを考えます。UEFIの大きな特徴として、一つのESP内に複数のブートローダーを共存させることができます。 ここでは既存のMBRブートのパーティションを残し、Windows 10インストール時に生成したESPにWindows Boot Managerと共存させる形でgrubをインストールすることにしました。/dev/sda1がESPであったとします。

# mount /dev/sda1 /mnt
# grub-install --target=x86_64-efi --efi-directory=/mnt --bootloader-id=grub

としたいのですが、このコマンドを実行するとUEFI経由で起動しろと怒られます。

efibootmgr: EFI variables are not supported on this system.

この状況でUEFIブートを行ったとしても、このgrubは起動できません。ブートエントリにgrubが追記されていないためです。しかしUEFIのブートエントリに追加しようにも、内部的にはefibootmgrを用いているようですが、従来のBIOSブートで起動したlinux側からはそれを編集することができません。UEFIシェル上でbcfgコマンドでブートローダーを追記してもよいのですが、失敗するのが怖いのでgrubの機能を用いて自動でやってもらいたいと思います。そのためにはUEFI経由で起動する必要があります。

UEFIシェルを触る

先述の理由からUEFI経由で起動したいのですが、BIOSからUEFIの設定を変えてgrubから起動しようとしても、今grub-installしたブートローダーはエントリには表示されないので、UEFIシェルを叩いて直接起動するしかありません。BIOSのブートオプションでUEFI shellを選択します。このシェル画面で先ほどgrub-installしたefiファイルを実行します。

> fs1:
> cd EFI
> cd grub
> grubx64.efi

こうしてから起動すると、grubのブート画面が立ち上がります。この画面でLinuxを選択するとEFI経由で起動したことになるので、再びgrub-installすることでファームウェアのブートエントリにgrubを追記することができます。こうすると、再起動した時にUEFI経由でgrubの画面が表示され、Windows 10を選択するとgrub経由で起動できるようになります。

以上のようにして、grubによるWindows 10とLinuxのマルチブートを行いました。ただしこの場合、BIOSブートでインストールされたWindows 7などを今までのgrub経由でブートしていた場合は、UEFI経由のgrubからでは起動できなくなります。

関連URL

uefi

Unified Extensible Firmware Interface - ArchWiki

EFI システムパーティション - ArchWiki

Rustの覚書

全体的に

postd.cc

https://japaric.github.io/discovery/

インストール

rustを手元の環境に導入する方法として、rustc(rustコンパイラ)を直に入れるほかにrustupと呼ばれるツールチェーン管理用のソフトウェアを介してインストールする方法がある。これはnightlyビルドやstableビルドなどが選べたり、バージョン管理が可能だったりするので、nightlyビルドでなければ通らないライブラリを使うときに個人的には便利であった。

blog.rust-lang.org

Cross Compile

github.com

によれば、

It's hard to find a cross C toolchain (and cross compiled C libraries) between different OSes (except perhaps from Linux to Windows). A much simpler and less error prone way is to build natively for these targets because they are tier 1 platforms. You may not have direct access to all these OSes but that's not a problem because you can use CI services like Travis CI and AppVeyor. Check my rust-everywhere project for instructions on how to do that.

ということだそうだ。

所有権・参照

qiita.com

qiita.com

Box, Rc, Cell, RefCell

agtn.hatenablog.com

qiita.com

ヒープ領域を確保するためのBox、C++のスマートポインタに相当するようなRcなど。

Optional / Result型

qiita.com

Logger

qiita.com

コマンドライン引数

qiita.com

文字列処理

qiita.com

HaskellにおけるHTMLのテンプレートエンジンを調査する

HaskellはWebフレームワークだけでもYesod, Snap, Happstackといった重厚長大型のフレームワークに加え、軽量なもの/API向けのものでもSpock, Scotty, Servantなど乱立しているが、Template Engineとて例外ではない。Blaze-html, shakespeare, mustache, stache, ede, lucid, heistなどこれもまた様々存在し、特にSpockやScottyといったフレームワークではテンプレートエンジン選択の自由度が高いので、どれを使おうかと思い、調べたのでここにメモを残す。

Template Engine

stackoverflow.com

stackoverflowでも何を使えばよいか、議論となっている。

stache

stache: Mustache templates for Haskell

Mustacheという汎用テンプレートエンジンのhaskell実装の1つ。 ただMustache自体の仕様として記法が簡潔でよいのだが、if文の分岐がBooleanのTrue/Falseしかできないなど、少し凝ったことをしづらい面がある。 ただAesonのインスタンスをそのまま渡せるのは心強く、Viewに送りたいデータを新しいデータ型として定義し、deriveJSONを呼んでおけば、あとはテンプレートにそのインスタンスを渡すだけでよいというのは手軽である。

記法は以下のような形。

Hi, {{name}}! You have:
{{#things}}
  * {{.}}
{{/things}}

こうすると、things配列の要素が.のところに順々に出力される。

Mustache

mustache: A mustache template parser library.

これも上と同じMustacheの実装。Data.AesonのValueを渡せるのはよいが、Maybe型の値のデータをみたとき、Nothingの時の値は空白が入っていることを期待したらnullが入っているというのはstacheと異なる点。そういった点で、stacheの時と同じmustacheファイルに対して同じ挙動を示すというわけではなかった。下の記事によれば、

Mustache templates in Haskell - Tutorials

it again makes simple things complex using Aeson's Value (good) and at the same time introducing its own Value type (with conflicting names of constructors and naturally not so numerous instances).

とのことで、Mustacheを使うぐらいであればstacheを使ったほうがよさそう。

ede

ede: Templating language with similar syntax and features to Liquid or Jinja2.

Mustache風味のHTMLベースのテンプレートエンジンだが、こちらのほうが表現力が高い。

qiita.com

こちらもData.AesonのValue型をObject型に変換し、それをテンプレートに代入してrenderしてくれる機構が備わっているので、テンプレートに与えたいデータをデータ型で用意しておけばよいのは変わらない。

--Unwrap a Value to an Object safely.
fromValue :: Value -> Maybe Object

記法はこんな感じ。

<div class="checkbox">
  {% for chara in characters %}
    <label class="checkbox-inline">
      <input name="chara" value="{{chara.value.name}}" type="checkbox">
      {{chara.value.name}}
    </label>
  {% endfor %}
</div>

if文では、比較演算子if-elif-elseと複数の条件で分岐させることもできるので、View側で凝ったことをすることも容易。

lucid

lucid: Clear to write, read and edit DSL for HTML

一方でこちらはhaskellの記法でHTMLを記述するDSL

ただSpockで使う場合、テンプレートを書き換えるごとにコンパイルしなおさなければならない。ede, stacheの場合は別ファイルで呼び出すので、コンパイルをし直す必要はないが、記法が誤っている場合は実行時エラーとなる。そう考えるとCompile時にValidateしてくれるlucidや、特にshakespeareではリンクのバリデーションも施してくれるので、これらのほうが型安全であると考えられる。

HTMLテンプレート?Lucidを使ってみた

Haskellの文法そのままなので、例えばリストの要素を列挙したい場合では

div_ [class_ "container"] do $
  h1_ [] "List"
  ul_ [class_ "list-group"] $
    mapM_ (li_ []) ["a", "b"]

などと書くことで、["a"], ["b"]の中身がliタグに囲まれて列挙される。

blaze-html

blaze-html: A blazingly fast HTML combinator library for Haskell

広く使われるHTMLライブラリではあるのですが、先述のLucidはこちらの改良版と言うか、blaze-htmlの問題点を解決したライブラリである。チュートリアルより、

import Text.Blaze.Html5 as H
import Text.Blaze.Html5.Attributes as A

userInfo :: Maybe User -> Html
userInfo u = H.div ! A.id "user-info" $ case u of
    Nothing ->
        a ! href "/login" $ "Please login."
    Just user -> do
        "Logged in as "
        toHtml $ getUserName user
        ". Your points: "
        toHtml $ getPoints user

記法はこんな感じで、これの何が問題かというと、下記のブログによればいくつかあるのだが、div, id, head, mapといった要素はbaseとconflictしているのでqualifiedして呼ばなければならないし、AttributeとElementの名前がコンフリクトするものがあるので、そうするとAやらHやらを頭に付けなければならない。結果としてコードが見にくくなってしまうのだ。それよりかは、Lucidのようにすべてsuffixに_をつけるほうが統一性があり、見栄えも良さそうだ。

Lucid: templating DSL for HTML

shakespeare

shakespeare: A toolkit for making compile-time interpolated templates

yesodで使われているテンプレートエンジン。hamletはこれにdeprecateされた。拡張子としては.hamletがHTML、.juliusがjs, .luciusCSSに対応している。 記法はこんな感じ。

<div .container>
  <h1> All Posts

  <div .jumbotron>
    <ul>
      $forall Entity id post <- allPosts
        <h4>
          <li>
            <a href=@{PostDetailsR id}>#{blogPostTitle post}

タグは閉じないで、インデントで親子関係を示す。HTMLに近い記法ができる一方でコンパイル時に変数が確実に埋め込まれる。たとえば@{}では型付きのURLが埋め込まれるため、それが有効なURLかどうかコンパイル時にバリデートされる。これがリンク切れを起こさない秘訣だ。変数の代入は#{}を使う。このとき、hamletではXSS attackを防ぐために適切にエスケープしてくれる。

制御構文は$から始まる行に記述し、if, elseif, forall, caseなど場合分けや、Maybe型への対応なども充実している。hamletはQuasiquotesでコード内部に埋め込むこともできるし、外部ファイルに記述することもできる。外部ファイルの場合はTemplateHaskellで参照され、コンパイル時に組み込まれる。

上記はyesodの場合で、これはscreencastから持ってきた例だが、yesodと無関係に使うこともできる。

www.yesodweb.com

sites.google.com

heist

heist: An Haskell template system supporting both HTML5 and XML.

snapというフレームワークで採用されているテンプレートエンジン。これは実際には試していないので、ウェブ上の例を見てみよう。

<bind tag="special">special-id</bind>
<div id="${special}">very special</div>

<bind tag="message">some text</bind>
<p><message/></p>

snapframework.com

heistの特徴となる主なタグはbindapplyで、bindはその名の通り変数を束縛し、 applyは<apply template="nav"/>のようにすると部分テンプレートを代入することができるらしい。Haskellからどう呼び出すかというと、公式サイトの例をみると

factSplice :: Splice Snap
factSplice = do
    input <- getParamNode
    let text = T.unpack $ X.nodeText input
        n = read text :: Int
    return [X.TextNode $ T.pack $ show $ product [1..n]]

というコードに対して、bindSplice "fact" factSplice templateStateとすると、<fact>タグにfactSpliceがbindされるので、<fact>5</fact>120になるとのことだ。

シェルコマンドでよく使う引数を書き留める

TL;DR

シェルコマンドの中で、しばしば自分が使っていて便利な引数、毎回検索するも忘れてしまって前回打ったコマンドをback-i-searchで探そうとするも見つからなくて困るものなどを記す。

diff

diff -y -B -b -i -W 200

  • -y : 結果を2行に表示
  • -W 200: 各行の幅を表示
  • -B : 空行を無視
  • -b : 空白スペースを無視
  • -i : 大文字・小文字の違いを無視

sort

sort -n -r -k 3,3

  • -n : 数値順に評価
  • -r : 逆順にする
  • -k : 並び替えるフィールドを指定する。上記の例だと3フィールド目。

tr

標準入力から標準出力へ、文字を変換・削除するなどして流し込むコマンド。

tr -d '\n'

  • -d : 引数の文字を削除する

less

less -N -S -s +F

  • -N : 行番号を付ける
  • -S : 長い行を折り返さず、1行で表示
  • -s : 空行を1行にまとめる
  • +F : 更新をリアルタイムに見る

qiita.com

qiita.com

time

/usr/bin/time -p -o FILE [cmd]

  • /usr/bin/time : シェル組み込みのtimeではなく、GNU timeを使う
  • -p : 互換性のある出力にする
  • -o FILE : 出力のファイル名を指定する

du

フォルダの容量を表示する

du -h --max-depth=2 [dir]

  • -h : サイズの接尾辞が付く
  • --max-depth : 再帰的に探索するディレクトリの深さの上限を指定する

tar

tar czvf file.tar.gz file tar xzvf file.tar.gz

  • c : 圧縮する
  • x : 解凍する
  • z : gzipにする
  • v : ファイル一覧を出力する
  • f : fの引数のアーカイブファイルを使う
  • j : bzip2にする

curl

curl -H 'Content-Type:application/json' -d "{\"session\": \"test\"}" -u user:pass [url]

  • -H : header
  • -d : パラメータをつける
  • -u : BasicAuthのユーザー情報

qiita.com

ps

プロセスを見る。

ps aux

  • a : 自分以外のプロセスも見る
  • u : ユーザー名が出る
  • x : 端末を持たないプロセスも見る

convert

ImageMagickのコマンド。identifyもそうだが、パッケージ名とコマンド名が一致しないので注意。

タイル状に切り抜く時のコマンド。

convert -crop 64x64 +repage in.png out.png

こうすると、64x64でタイル状に左上から切り取ってくれる。ただし、割り切れずに端数がでる場合は端数サイズのファイルが出力されてしまうし、出力ファイル名はout-1.png,out-2.pngのようになるので、sortするときに文字順で並べるとout-1.png,out-10.png,out-11.png...のように並んで困ることになる場合もある。

Imagemagick - code snippets

xargs

xargs -P 22 -n 2 -t -I {} [cmd]

  • -P : 指定した個数のプロセスを立ち上げて並列実行
  • -n : cmdに渡す引数の個数
  • -t : コマンドの実行内容を表示
  • -I : [cmd]の部分に引数で渡した{}を使うと、その部分にxargsで渡される引数が入る。
    • -i : -iも-Iと同様で、引数を省略すると自動で{}が採用されるが、deplecated.

orebibou.com

d.hatena.ne.jp

ただしxargsからパイプでファイルに書き込みたいと思って、> output.txtなどと書いても、プロセスを並列化していると複数のプロセスから同時に書き込まれるので、1つのプロセスから書き込まれる内容が別々の行にばらけてしまうことがある。そういった諸々の問題が面倒なので、下のコマンドを使うこともある。

parallel

xargsより高性能に並列処理を行ってくれるコマンド。このGNU parallelは、apt-getなどで別途導入する。

bicycle1885.hatenablog.com

GNU Parallel

シェルスクリプト(bash)

bash -x hoge.sh

  • -x : 実行するコマンドも同時に出力する
  • -c : 引数の文字列をシェルコマンドとして実行する

shellscript.sunone.me

モニタリングツール

htop

プロセスをモニタリングするtopコマンドの拡張で、見やすい。 htop 上でキーをたたくと、表示様式を変更することができる。F1キーをたたけばヘルプが見られる。

  • u : ユーザーを限定してプロセスを表示
  • H : ユーザープロセスのスレッドを隠すか表示させるかをトグルする
  • l : lsofで開いているファイルを読む
  • s : straceで読んだシステムコールを読む

iostat

ioの状況を表示するコマンド

bmon

ネットワークアダプタの状況を表示するコマンド

その他

80 Linux Monitoring Tools for SysAdmins - Server Density Blog

入出力制御

qiita.com

Haskellで参考にしたもの

Web Framework

Scotty / Spock

Rubyで言う所のSinatraのような軽量フレームワークhaskell版。ScottyよりSpockの方が、waiに準拠している上に機能も充実していて良いらしい。

Spockの紹介記事は以下。

qiita.com

ScottyをHerokuで動かしてみたサンプルアプリは

github.com

Yesod

Yesodのすごいところは、shakespeareのおかげでビューにまで型付きの制約があるところで、このおかげでリンク切れとか起きないらしい。(もしリンクが切れるようなことがあれば、それはコンパイルが通らない。)

またketerと言うデプロイマネージャーは、ローカルでコンパイルして、実行に必要なファイルをすべてまとめてサーバーにscpし、ダウンタイム0でデプロイしてくれるようにできるらしい。とても便利。

公式のScreecastsには、わずか40分程度!で簡単なブログを組み立てる動画が見られる。

HTMLエスケープやXSSを防ぐ機構についてはライブラリが面倒を見てくれるため、我々はそういったことに気をつかうことなく安心してWebアプリを書くことができる。

www.yesodweb.com

Other

Web/Comparison of Happstack, Snap and Yesod - HaskellWiki

テンプレートエンジンについては記事を書きました。

sharply.hatenablog.com

DB操作をする

YesodのDatabase.Persistentが、sqlite, mongoDB, postgresSQLなどのDBとのアダプターとなって、マイグレーションを自動でやってくれるとか便利。

www.yesodweb.com

qiita.com

rf0444.hatenablog.jp

http://blog.fujimuradaisuke.com/post/26887032662/haskell-de-json-web-api
blog.fujimuradaisuke.com

Libraries

d.hatena.ne.jp

http://haskell-distributed.github.io/

実際にこれを使って分散処理を書くのがやりやすいかというと、やはりもう少しダイナミックに型を扱える言語の方が書きやすいのかもしれない。

チュートリアル

1. Getting Started

  • IntervalMap

区間を保持する構造のhaskellにおける実装。

github.com

Haskell IntervalMap

  • Aeson

Template Haskellを用いて、dataの定義からderiveJSONするのがスマートそうな気がします。

qiita.com

Data.AesonでJSONを扱う | saito's memo

文字列型

bicycle1885.hatenablog.com

qiita.com

Blaze.ByteString.Builder

Other

例えばm [a] => [m a]にする関数が何かを知りたいと思った時、Hoogle で検索するのが便利そうです。初心者なのでコンパイルが通らない時に型の帳尻合わせをしたくなるので、そういった時に重宝しました。

Hoogle

github.com