よく見ると文鳥が左目をよくつむっているようだった. 例えば指で目の周りをなでてみると, 右目と比較しても過敏によくつむる. そんな刺激をしなくても餌を食べるときにやたら目をつむり, 決まってそれが左目だった.
調べると, 一般に鳥がじっと目をつむってるのは眠ってるか眠たいときでもない限りは異常であるとのこと. 片目であっても両目であっても, 餌を食べるというときは, 常に周りを見わたして警戒するのが正しい鳥の姿.
ではなぜ目をつむるのか. 一番有りえるのが結膜炎であるらしい. これは目そのものに傷が入ったりして炎症になっているパターン. この場合は目薬で治す.
よく見ると脚を使って目(の周囲)を掻くような仕草までしている. 私は慌てて, 評判を調べつつ適当な小鳥専門病院に行ってきた. なんだかよくわからない機械で目を見て, 結膜炎ではないと結論を下された. 嗉嚢の中のなにかの採取をし, またフンを取って, 菌の検査をしてもらった. すると嗉嚢に活動螺旋菌がいることがわかった. その菌は文鳥の雛に一定の確率でいるものだが, いないに越したことはないし, 目に違和感を感じてるのは恐らくこれが原因だろうと言われた. なんだかよくわからないが, その獣医の説明によれば, 消化器官にいる菌が目にまで作用するものらしい. また同時に, くしゃみや咳をするようになったら悪化してる証拠なので, その場合は至急に連絡せよとも言われた.
抗生物質の飲み薬を二種類処方された. これを毎日二回, 嘴に垂らして飲ませる. 飲ませ方の説明も何もなく, 飲み薬というくらいだから, 嘴をこじ開けて飲ませるのかと思ったけど, もっと簡単に飲ませる方法がある. 嘴というのは, その隙間に垂らしてれば勝手に浸透圧で入っていって, 文鳥はそれを飲んでしまうものらしく, それを利用して飲ませればよいらしい.
この動画が参考になった. 肝心の液を垂らすシーンが手で隠れて見えないんだけど, 説明だけ聞けばわかる.
初めて病院に行ってから一週間抗生物質を飲ませ続け, 再び病院で二度目の検査. 今度は螺旋菌は全くいなくなってたが, 別な菌が多いのでまた薬を飲ませ続けましょうと, 再び同じ薬を処方されてしまった. 診察料3000円で, 二種類の薬代が合計3500円. 全て併せて一回の診察で 6500 円. これを二回, 2週連続で払ったことになる. もちろん社会保険は適用されない. あんなに高い高い保険料を払ってるのに.
それからまた一週間抗生物質を飲ませ続けて, 今日三度目の診察. やはりまた嗉嚢とフンの菌検査をしてもらい, 普通の常在菌レベルだということで, 薬の投与は終わった. ただ嘴の色が淡すぎるのがおそらく貧血気味だろいうと言われ, タンパク質を含む餌を与えましょうだとか, シードはやめてペレットにしましょうといった指南を頂いた.
今日は薬の処方も何も無かったので安くて 2200 円だけで済んだ. 初めての診察のときは, お金なんていくら掛かっても, と思ったものだが, 2週連続で6500円も取られたときには, さすがにこんな出費が毎週続くくらいならよっぽど, もう病院に行くのなんてやめようかと思ったものだ.
明らかに不自然な症状を見て私は慌ててググりまくった. 得られた中で本当に正しいと思われた情報は次の2つ.
1つは専門の病院に行けということ. 小鳥は小鳥専門の病院を探せ. 犬猫しかみない病院に連れて行っても時間の無駄である.
1つに心配ならとにかく病院に行けということ. インターネットに欲しい情報はない. 聞きたいことは掲示板じゃなくて獣医に聞け. お金はもちろん掛かる. 嘘の情報で無駄な日を過ごすか, 確かな情報をお金で買うか選べということである. 後者を選ぶなら, そのタイミングは早ければ早いほど良いと確かに言える.
今日はラーメンを食べました. 人生で最後のラーメンということにしたい.
世にはいくつもの, 設定ファイル用言語というものがある. メジャーどころだと
私はこのどれにも一定の不満がある.
人間にとっての読み書きのしやすいものはどれか. 私は INI \(>\) YAML \(>\) JSON だと思う. JSON が一番最悪なのは明らかで, だからこそ拡張の JSON5 や Jsonnet がある. YAML は JSON と比較したときにあたかも human readable であるかのように紹介されることが多いが, それを鵜呑みにしてる人間は本物の YAML を知らずに済んできた幸運な人だと思う. 実際, 20行程度までで済むような設定ファイルを書くだけなら YAML は十分良いと思う.
テンプレート機構, 主に関数またはマクロについて. なんだかんだ, 欲しい. 基本的に設定ファイルというのは素朴に設定値を列挙するだけである. 今挙げた中で唯一 Jsonnet は data templating language を自称しているだけあって, この機能を持つ. Jsonnet のことは JSON を出力するテンプレート言語だと言ったほうが正確だ. こいつはチューリング完全な関数の機能があって, 無限ループを仕込むことが出来る. JSON は JavaScript のサブセット言語だったが, Jsonnet は単に JavaScript の言い換えに過ぎないと思う. 字句的に置き換えるだけのマクロ機構としての関数は便利だが, チューリング完全にまでする必要はないと思う. 設定ファイルを書くことが目的なら. 「人間が十分賢く十分慎重である」ならば機能が強すぎることは何も足枷ではないが, 私が知ってる人間は全てが全て愚かなので, 強すぎる武器を与えないに越したことはない. ちょうど良い機能だけを持った道具を与えるべきだ.
型システムについて. これらの設定ファイルは, 基本的に何でもありだ. 例えば JavaScript が [1, 2.3, "Hello", []]
という配列を許すのと同様に, これを JSON は許すし, YAML にはこれに対応する表現がちゃんとある(ところで INI には配列なんてデータ構造はない!). こんな配列を表現出来るのが便利だという人はやっぱり, 人間性善かつ完全説を信じすぎているのであって, いっそ表現できないようにするのが良いに決まってると私は思う.
ところで, 弱い型付言語を触ってると, ふつう数値はせいぜい int と float くらいの区別しかしないで, 自然数と整数を区別しないのが悪い文化だと思う. 例えば配列の長さという数はマイナスになることがないのだから, 自然数に制限した方がいいに決まってる. 例えば人間の年齢は自然数だし, 仮想マシンに与えるメモリ量も自然数だし, なにかの間違いでマイナスの値が出てきたらオーバーフローをさっさと検知してあげるのが人間への優しさに決まってる.
というわけで, 以上を解決する言語を設計する. 名前を cumin とした.
こんな日記をうだうだ書いたのは, 結局どんな言語にすれば私は満足出来るのかアイデアを今正にまとめてる最中だからである. つまり, まだ結論がちゃんとは出ていない. 今のところは, こんな感じにしようとは思ってる.
Rust 風のシンタックスを装っていて, let
によるフィールドへのデータ束縛で記述する. フィールド名のすぐ後ろの : ...
はデータの型を言っている. 適当な型推論は乗せて, これは省略可能であるようにもしたい.
// cumin
let x: Nat = 1;
let y: Int = -1;
これが
// JSON
{"x": 1, "y": -1}
に対応する.
jsonnet で書くなら
// jsonnet
local x = 1;
local y = -1;
{x: x, y: y}
という具合だろう.
jsonnet の構造はこのように, 中で使うプライベートなデータを local
として宣言していって, 最後に export したいデータを1つぽんと置く形になっている. テンプレート言語という文脈で言うなら, テンプレートの中で使うデータを初めに列挙して, 最後にテンプレートを1つ書く, という構造になっている.
一方で cumin は, let
で宣言した変数全てを export してしまうことにしている. これが良いのか悪いのかはまだ迷っている. 別に cumin はテンプレートエンジンではないし, INI とか普通のを見るとこっちのが自然だし, とも思っている.
ところで, そうすると cumin が export できるデータというのは JSON で言うところの辞書データに限定されることになる. 例えば配列1つを export することが出来ず, {"data": [1, 2, 3]}
のように包む必要が出てくる. これは包めば表現できることだし, そもそも初めから, 全ての JSON データを表現可能にするつもりがないというのがある. さっき型システム云々のところで言ったような奇妙な配列はそもそもエラーにしたいわけだし.
というわけで JSON から cumin への変換は常にはできないことになる. ただしその逆に cumin から JSON への変換は常に出来るようにしておきたい. cumin の処理系として cuminc
を開発するつもりだが, これは JSON を吐くコンパイラとして作るつもりだ.
cumin は struct 構造体を持つ. これは Rust で言えばそのまんま struct
, 或いは C/C++ で言うところの構造体の宣言である.
struct X {
x: Nat,
y: Int,
}
例えばこの構造体 X
はは {"x": ..., "y": ...}
という形式の辞書を表現している. ここで x
, y
のデータ型はそこに書いてあるとおり Nat, Int でなければならない. そして x
, y
以外のフィールドが余計についてたら駄目だし, 逆に足りなくても駄目ということにする. フィールドが無くてもいいこともあるかもしれないので, None
をサポートする Option
型やデフォルト値の設定も出来るようになると便利だろうと思う.
さてこの X
構造体を使うと,
let p = X(1, -1);
と書ける. これは {"p": {"x": 1, "y": -1}}
を表す. いちいち {"x": 1, "y": -1}
と書くのを X(1, -1)
で書けるので, 簡潔に書けるようになるし, 可読性にも貢献するだろう. 限定的ではあるが, struct を使うことでマクロ的に記述を減らすことが出来る.
普通にマクロそのものを提供するかは, ちょっとまだ考えてる. 上に書いたことで出来る範囲で十分なんじゃないかと.
プログラマブルであること. 数値の四則演算であったり, 配列の結合や map といった基本的な演算をサポートすること.
let x = [1, 2, 3];
let y = x.map(|val| val + 10);
let all = x + y;
これは
{
"x": [1, 2, 3],
"y": [11, 12, 13],
"all": [1, 2, 3, 11, 12, 13]
}
を表す. ここで x
と y
は all
を作るためのデータで, 表に出したいわけじゃないとする. ただの {}
は変数スコープを作る.
let all = {
let x = [1, 2, 3];
let y = x.map(|val| val + 10);
x + y
};
ここがやっぱり迷ってる部分で, Jsonnet のようなデータ+テンプレートの二部構成にするなら,
let x = [1, 2, 3];
let y = x.map(|val| val + 10);
x + y
と書ける. こうやって見ると, こっちのほうが簡潔じゃないかと思いもする.
ていうか、
let x = {
let x = 2;
x + 1
};
この {}
の中は 3
というデータを表していて, {"x":2}
というデータではない. 一方で全体は {"x": 3}
を表すということになっていて, キレイな再帰的データ構造になっていなくて気持ち悪い.
これを採用するならそのjsonnet方式を採用した方がずっといい.
let x = [1, 2, 3];
let y = x.map(|val| val + 10);
x + y
でもって [1,2,3,11,12,13]
というデータを表す.
或いはもっと別な文法にする. 例えば
x + y
where {
let x = [1, 2, 3];
let y = x.map(|val| val + 10);
}
うーん, これはちょっとな...
だいぶやれるようになってきた. 前回色々言ったけど, 結局 jsonnet のように, まずデータ型や細かいデータの定義をつらつらと書いて, 一番最後に, 1つだけエクスポートするようなデータをまるでテンプレートを書くかのように書く, というスタイルになった. こちらのほうが単純に文法がキレイというのが1つ, 変数名が衝突するような場合のチェックが面倒(衝突する場合は variable hiding させたい)というのが1つ.
cumin/commit/d4015caf79e86acf45f4ce842218fb768ebc375a
こんなのが動く.
struct Point {
x: Int,
y: Int,
}
let p = Point(2, 3);
enum Z {
Z1, // Z is this,
Z2, // xor this.
}
let x = "hoge";
let y = "fuga";
let z: Nat = 0;
// 上書き!
let z = Z::Z2;
struct AllData {
p: Point,
z: Z,
str: String,
}
// Exporting this
AllData(p, z, x + y)
これについて cuminc
は次を吐く.
{
"p": {
"x": 2,
"y": 3
},
"z": "Z2",
"str": "hogefuga"
}
struct は辞書に変換されるし, +
は数値の加算または文字列結合として計算される. enum の扱いややや困るが当然 JSON にはプリミティブな型しかないので, 列挙子の名前そのママを文字列として吐くことにした.
まだまだ色んなものが足りてない
{{ x=1, y="hoge" }}
という文法を用意するX { field=val }
形式のコンストラクタ+
しかない次はやるか未定
情報幾何では距離ではなくダイバージェンスが要になることがよくある. というかめちゃくちゃ基礎にそれがある.
大雑把に言えばダイバージェンスというのは, 距離から対称律 \(d(x,y) = d(y,x)\) を 除いた ものである. 例えば KL ダイバージェンスが有名だが, これは「点 \(x\) から点 \(y\) へのダイバージェンス」というように, 行き先と元を明確にする必要がある. 点 \(y\) から点 \(x\) へのダイバージェンスとは一致しないからである.
なんだかこれが本質のような気がしてならない. ダイバージェンスは局所的には対称律が成り立っていて距離として振る舞う. 勝手に距離のように思っているものは実はダイバージェンスで, それを近似的に距離だと扱ってきたのかもしれない.
点を適当なベクトル表示したときに, 距離をL2距離(内積)で決めてしまうことがとてもよくある. これは距離である. 典型例は行列分解である. 内積とは行列積のことに他ならない. アイテムどうしの距離を内積によって決めてしまう. ここから対称律を取り除くと, それだけで表現力が豊かになる. 損なわれるのではない. できることが多くなるのである. 例えば時系列の情報が込められる. コレの後にはコレが来やすいというのをダイバージェンスで表せる. 因果関係なんかもそうだと思う.
表現力としては当初欲しかったものが十分手に入ったと思ってる. 機能はまだまだだし, 仮にこれを人が使いだしたら止めるレベルではあるけれど, これをそのまま拡大すればいいだけだと思えるくらいには一通り揃った. というわけでリリースタグを打った. v0.9.0
からこの3つ目の数字をひたすら増やしていって, これ以上できることが無いと思えるようになったら v1.0.0
にするつもり.
設定ファイルという静的なデータを表現するだけの言語のその処理系とはなにか. 私はそれを JSON への変換器ということにした. cumin compiler なので cuminc
というコマンド名にした.
基本的な文法については散々書いた. そこからの進捗を語るなら, まずは無名 struct, そして環境変数とブロックを追加した.
無名 struct は要するに中身に何の制約もないただの辞書である.
{{
x = 1,
y = {{
z = 2
}}
}}
$ cuminc test.cumin
{"x":1,"y":{"z":2}}
環境変数は常に文字列で, $X
とか ${X}
で参照できる.
{{
env = {{
shell = $SHELL
}}
}}
$ cuminc test.cumin
{"env":{"shell":"zsh"}}
これはシェルスクリプトを意識した書式にしている. 環境変数はその場でセットして cuminc
することで, 即席のテンプレートとしても役立つ.
またデフォルト値が使えると便利だと思う. これもシェルスクリプトそのままの書式を流用して ${X:-HOGE}
と書けるようにした.
{{
hoge = ${HOGE:-default}
}}
$ cuminc test.cumin
{"hoge":"default"}
$ HOGE=hello cuminc test.cumin
{"hoge":"hello"}
最後はブロック. これは Rust そのものを知っていれば, あるいは ML から類推してもらえれば特に不自然なことはないと思うけれど,
{}
で括って,
{
文;
文;
文;
式
}
と書いて, この {...}
を評価すると何を計算するか. 中の文を順に実行して最後に式を評価する. そしてその値を {...}
全体の評価結果にする. ここで ;
は単に文と文, または文と式の区切り文字でしかないことに注意. 文末につける終端文字というわけではない.
cumin で言う文というのは三種類しかなくて,
のいずれかである. 構造体, 列挙子, let 束縛で作られる変数はその {}
の中だけで参照できて有効である.
例えば,
let x = {
let a = 1;
let b = 2;
a + b // ここでは a, b が見える
}; // x には a+b の結果が入る
// ここでは a, b は見えない
{{
three = x
}}
$ cuminc test.cumin
{"three":3}
プライベートな変数を作るのに便利だし, それよりも, このデータはこのデータを構築するために必要だという, 意図表示に役立つ.
ぼーっとしていると生活について考えてしまう. そんな状態で自分の誕生日を迎えたくないので衝動的に言語を作り始めた. おかげでコーディングしながら日を跨いだことにも気づかないことに成功した.
ある言語で表現出来るクラスのサイズというものを仮に有限の値で表せるとしたら, そこから新たに追加したい機能は, それに比例するかもしれない. これが出来るなら当然あれも欲しくなる. 最初だからそう思うだけかもしれないけど. どこかでゼロに収束してくれるのかな.
/github.com/cympfh/cumin/releases
衝動的に文法を設計してしまった感が否めなくて, 後から追加するのに苦労している. というか特に命名に苦労してる.
Bool Expression は Bool といいつつ正確には Bool と数式を含む式で, 純粋な数式(例えば 1 + 2
)も Bool Expression ということになっている. なんだそれは.
文鳥の頭頂部から少しずつ換羽してきていている. 新しく生えた羽はまだ針みたいに尖ってるばかりで見た目が悪い.
先週見た. ネタバレだらけの感想を書いた.
行こうとか思ったけど, テレビを付けたら人で大賑わいの鎌倉が流れてて, 行くのをやめた.
パンティーアンドストッキングがやってたので, それを見ながら, 溜まりに溜まった仕事をやった. 偶然にも 11/24 までにやれという仕事が2つと, 11/25 までにやれというい事が1つあったのを, 11/23 の深夜にやった. 仕事というのは, 量と内容を把握するまでが9割で, 残りの1割は惰性で出来る.
Windows にも, まともなタイル型デスクトップ環境が欲しい
思うに, UI/UX というのは UX という名前の通り体験なので, その良さとか悪さは体験しないとわからない. 一度, 本当に良いというものを体験してしまうと, 何を触っててもそれと比較してしまう. 口で言うだけでは伝わらない良さが体験にはある.
私は Linux では i3wm を使っていて, それが理想だと思っている. タイル型ウィンドウマネージャを触ったことのある人間というのは極小数派だと思う. 体験したことの無い人たちに, 口でその良さをいくら言っても伝わらない. できるだけ上手にデスクトップ上にウィンドウを配置するショートカットだったりアプリはあるが, そうじゃないんだよなあ. 全然別物なんだよなあというのが伝わらない.
「ふれない」とも「さわれない」とも読める.
見た目ゴミ箱だと気づかないようなのが良い. 今使ってるのが /dp/B07MZ9VVCJ/
これ. やっぱり木製は良い. いつも作業してる机の下にこれを置いてる. 中にセットしてるレジ袋が絶対外から見えないようになってる. ただしこれは袋の付け方がややこしくて, 実用性よりインテリア性に偏りすぎとも思う.
文鳥のケージのすぐ下に, レジ袋を置いてて, 何かと出るゴミをここに入れてる. 主に文鳥のフンを拭き取ったティッシュなんかなので, とにかく見た目だけキレイにしたい. 鳥のフンはほとんど匂いもしないけれど, でもできれば蓋かなんかで封じ込めたい気持ちもある. 或いは入り口が狭くなってるとか, そういうのでもいい. なんかいいのないかな.
効果があるのかよくわからない
整数の範囲内の幾何. プロコンで時折求められるもの.
短編2つと長編1つ. 3つとも, これ, 実は必ずしも涼宮ハルヒの憂鬱のキャラクターである必要はないな. そらこんだけ間空いてれば, 作者の興味も全然違うものになってるだろうと思う.
ところで, キーワードレベルで出ているが, 涼宮ハルヒというキャラクターは自分自身が全能であることに気づいていない全能の神である, 或いはその疑いがあるというキャラクターとして描かれている. 有名な思考実験として全能は自分自身が持ち上げられない石を作ることが出来ない, 或いは持ち上げることが出来ないという全能のパラドックスがある. 谷川流がそれを知らないわけはないので, それを無視するわけがない. そこで今回最後の最後に「自分が全能であることを知らない神」(p.405)というキーワードを出している. 少なくとも自分を全能だと思わず常識的な振る舞いを徹底すれば, そのような石を作り出そうとはしないから, このパラドックスは回避できるわけだ. というのは対症療法であって根本的なパラドックスの回避になるのか疑問だが, 谷川流はそう考えているのかもしれない, と思った.