Sat Nov 07 2020

文鳥が片目をよくつむる

よく見ると文鳥が左目をよくつむっているようだった. 例えば指で目の周りをなでてみると, 右目と比較しても過敏によくつむる. そんな刺激をしなくても餌を食べるときにやたら目をつむり, 決まってそれが左目だった.

調べると, 一般に鳥がじっと目をつむってるのは眠ってるか眠たいときでもない限りは異常であるとのこと. 片目であっても両目であっても, 餌を食べるというときは, 常に周りを見わたして警戒するのが正しい鳥の姿.

ではなぜ目をつむるのか. 一番有りえるのが結膜炎であるらしい. これは目そのものに傷が入ったりして炎症になっているパターン. この場合は目薬で治す.

よく見ると脚を使って目(の周囲)を掻くような仕草までしている. 私は慌てて, 評判を調べつつ適当な小鳥専門病院に行ってきた. なんだかよくわからない機械で目を見て, 結膜炎ではないと結論を下された. 嗉嚢の中のなにかの採取をし, またフンを取って, 菌の検査をしてもらった. すると嗉嚢に活動螺旋菌がいることがわかった. その菌は文鳥の雛に一定の確率でいるものだが, いないに越したことはないし, 目に違和感を感じてるのは恐らくこれが原因だろうと言われた. なんだかよくわからないが, その獣医の説明によれば, 消化器官にいる菌が目にまで作用するものらしい. また同時に, くしゃみや咳をするようになったら悪化してる証拠なので, その場合は至急に連絡せよとも言われた.

抗生物質の飲み薬を二種類処方された. これを毎日二回, 嘴に垂らして飲ませる. 飲ませ方の説明も何もなく, 飲み薬というくらいだから, 嘴をこじ開けて飲ませるのかと思ったけど, もっと簡単に飲ませる方法がある. 嘴というのは, その隙間に垂らしてれば勝手に浸透圧で入っていって, 文鳥はそれを飲んでしまうものらしく, それを利用して飲ませればよいらしい.

この動画が参考になった. 肝心の液を垂らすシーンが手で隠れて見えないんだけど, 説明だけ聞けばわかる.

初めて病院に行ってから一週間抗生物質を飲ませ続け, 再び病院で二度目の検査. 今度は螺旋菌は全くいなくなってたが, 別な菌が多いのでまた薬を飲ませ続けましょうと, 再び同じ薬を処方されてしまった. 診察料3000円で, 二種類の薬代が合計3500円. 全て併せて一回の診察で 6500 円. これを二回, 2週連続で払ったことになる. もちろん社会保険は適用されない. あんなに高い高い保険料を払ってるのに.

それからまた一週間抗生物質を飲ませ続けて, 今日三度目の診察. やはりまた嗉嚢とフンの菌検査をしてもらい, 普通の常在菌レベルだということで, 薬の投与は終わった. ただ嘴の色が淡すぎるのがおそらく貧血気味だろいうと言われ, タンパク質を含む餌を与えましょうだとか, シードはやめてペレットにしましょうといった指南を頂いた.

今日は薬の処方も何も無かったので安くて 2200 円だけで済んだ. 初めての診察のときは, お金なんていくら掛かっても, と思ったものだが, 2週連続で6500円も取られたときには, さすがにこんな出費が毎週続くくらいならよっぽど, もう病院に行くのなんてやめようかと思ったものだ.

ところで, ペット関連の情報をインターネットで調べるということについて.

明らかに不自然な症状を見て私は慌ててググりまくった. 得られた中で本当に正しいと思われた情報は次の2つ.

1つは専門の病院に行けということ. 小鳥は小鳥専門の病院を探せ. 犬猫しかみない病院に連れて行っても時間の無駄である.

1つに心配ならとにかく病院に行けということ. インターネットに欲しい情報はない. 聞きたいことは掲示板じゃなくて獣医に聞け. お金はもちろん掛かる. 嘘の情報で無駄な日を過ごすか, 確かな情報をお金で買うか選べということである. 後者を選ぶなら, そのタイミングは早ければ早いほど良いと確かに言える.

ラーメンを食べた

今日はラーメンを食べました. 人生で最後のラーメンということにしたい.

cumin

世にはいくつもの, 設定ファイル用言語というものがある. メジャーどころだと

私はこのどれにも一定の不満がある.

人間にとっての読み書きのしやすいものはどれか. 私は 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]
}

を表す. ここで xyall を作るためのデータで, 表に出したいわけじゃないとする. ただの {} は変数スコープを作る.

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);
    }

うーん, これはちょっとな...