だいぶ体調が復活してきた。
diary
health
体調がよくなってきた。
febc
今日のFEBCは神水教会だった。 熊本にいたころ何度か訪れたことがある。
また、日本福音ルーテルの式文は馴染んでいるものであり、各種のフレーズや音程もすぐに口から出てきた。
これは自分の悪いところなのであるが、礼拝の内容をすぐに忘れてしまう。 何度も似たような話を聞いているからでもあるが、 なんというか身が入らない。 やはり、直接礼拝堂に赴かないと、私は集中できないのだろうか。
pray
主よ、あなたの声に耳を傾けさせてください。
弱っているときも、しっかりしているときも、あなたが共におられることを私の心に思い出させてください。
food
ご飯をそこそこ多く食べることができるようになった。 運動を二日に一回しっかりとするようになったおかげでもあろう。 また、無理な温冷シャワーを避け、仕事をする日の朝だけにしたことも実は効果があるのかもしれない。
また、食事の好みにおいては、発酵食品が最近は好んで食べるようになった。 特に、納豆については、毎朝食べるようになった。 一種類だけの発酵食品をとるのはあまりよくないので、べったら漬けも今日は買った。
今日の勉強
rust
TRPL pp.267-278
リファクタリングの方針
- 機能を小分けにして、各関数が1つの仕事のみに責任を持つようにするのが最善
- 設定用変数を1つの構造に押し込め、目的を明瞭化するのが最善
- エラーメッセージで間違った情報をユーザーに与えないようにする
- エラー処理のコードを全て一か所にまとめ、将来エラー処理ロジックが変更になった時にメンテナンスで一か所のコードのみを考慮すればよいようにするのが最善
機能のこわけ
バイナリプログラムの個別の責任を分割するためのガイドライン
- プログラムをmain.rsとlib.rsに分け、ロジックをlib.rsに移動する
- 解析ロジックが小規模な限り、main.rsにおいてもよい
- 解析ロジックが複雑化の様相を呈し始めたら、mainから抽出してlibに移動する
mainに残るのは呼び出し、他の設定、エラー処理であり、読めばその正当性を評価できるだけの小規模なもの。libにはロジック全てをおき、テスト可能にする。
引数関数を抽出し、コマンドライン引数と変数がどう対応するかを決定する責任をmainから剥がす。
設定用変数を構造体に押し込める
正しい抽象化がまだできていない兆候:
- タプルを返して、即座にタプルを分解し、再度個別の値にしている。
- 2つの値の関数がタプルにまとめていること以外、データの構造に、その意味を載せていない。
そこで、構造体に置き換え、構造体とフィールドそれぞれに意味のある名前をつける (Configという名前、それぞれのフィールド名、それで、フィールド名同士の関連を明らかにし、また、構造体名でプログラムの振る舞いを設定することという目的を明確に伝えられる。)
文字列スライスではなく、Cloneを使って、Stringをフィールドに持たせる。 Cloneは価値ある代償である。
- 非効率さ
- 総コピーが生成されるので、文字列データへの参照を保持するよりも時間とメモリを消費する
- RustaceanはCloneを避けるが、サイズや回数によっては、とりあえず使ってもよい
- もっとRustの経験を積んでから考えろ
- RustaceanはCloneを避けるが、サイズや回数によっては、とりあえず使ってもよい
- 総コピーが生成されるので、文字列データへの参照を保持するよりも時間とメモリを消費する
- 単純さ
- 参照のライフタイムを管理する必要がない。
構造体のimplに変える
parse関数の目的が、Configインスタンスを生成することであるから、Config構造体にimplブロックで紐づくnew関数に移すことで、1つのリファクタリングができる。
エラー処理の修正
添え字アクセスする前に、スライスが十分長いことを実証するチェックを追加し、それをResult型で処理する。
- チェックに失敗したら、panic!マクロを呼び出す案。
- panic!の呼び出しはユーザーに与えたくない追加の情報を含んでしまう。
- panic!の呼び出しは仕様の問題よりもプログラム上の問題により適している
- Result型を返すようにする
- panic!を呼び出す代わりにErr値を返し、
- ユーザー向けのより実用的なエラーに変換することができる
- Config戻り値をOkに包んで返す
- panic!を呼び出す代わりにErr値を返し、
- Result型を処理する
unwrap_or_else(|err| {...})
- Okならunwrapして
- Errならクロージャー内でコードを呼び出す
- クロージャーは自ら定義して引数として渡す匿名関数
process::exit(n)
:- プログラムを即座に停止し、渡された数字を終了コードとして返す
- 0以外の終了コードは、我々のプログラムを呼び出したプロセスにプログラムがエラー状態で終了したことを知らせる慣習
プログラムのロジックの抽出
セットアップやエラー処理に関わらない部分の全てを保持するrun
関数へ抽出
Result<(), Box<Error>>
を返すようにする
Ok(())
でユニット型の値をOk値に包む- runを副作用のためだけに呼び出していると示唆する慣習でもある
Box<Error>
はトレイトオブジェクト- 関数がErrorトレイトを実装する型を意味し
- 具体的に型を指定しなくてもよい
- 異なる型のエラー値を返す柔軟性を得る
- expectではなく?演算子を使うようにする
- ?演算子は呼び出し元が処理できるように、失敗時に、現在の関数からエラーを返す。
返されるResultの処理で、エラーを検知することのみに興味があるのであれば、unwrap_or_else
ではなくif let
でErr値を返したかどうかを確認する。
isabelle
Concrete Semantics pp.175-178, pp.179-180
最小のfixpointをcomu0ptueする方法と、その決定可能性の補題。
rvars
の導入
Whileの場合のLの実行可能な定義の確認。
Forward/Backward
- Forward Analysis: プログラムの最初から最後へと情報を伝播する
- Backward Analysis: プログラムの最後から最初へと情報を伝播する
- この前後の捉え方の違いがわからない。
May/Must
- May Analysis: あるpathにおいて、与えられた性質が真かどうかチェックする
- Must Analysis: 全てのpathにおいて、与えられた性質が真かどうかチェックする
分類
- Definite Initialization: Forward Must
- 変数はそれが使用される前に、全てのpathにおいて、assignされていなければならない
- Constant Propagation: Forward Must
- 変数はそれが使用される前に、全てのpathにおいて、何らかのconstantを持っていなければならない
- Live Variable Analysis: Backward May
- あるpathにおいて、ある変数があり、それが書き換えられる前に、使われているならば、変数はliveである
11章のDenotational Semanticsに突入。
Denotational Semanticsは、あるsyntacitc constantに対して、その合成されたものの意味は、部分の意味を引数とする原始再帰的な関数として定義される
- avalやbvalはdenotational semanticsであるが、
- Big_Stepはそうではない
WHILE b DO c
は、WhileTrueにおいて、b
とc
の意味だけではなく、WHILE b DO c
の意味に機能的に依存する
Denotational Semanticsのモチヴェーション:
- 証明は、
- 等式推論の単純で有効な証明原理と
- syntax上の構造に関する機能法とによって、
- 実行される
1on1
『ヤフーの1on1』を読み終えた。
後半は、ヤフーはこういう会社で、だから1on1を重視して、こう活用している、と結構会社の文化紹介を強く感じる内容であった。 が、全体のまとめという側面もあり、文化紹介であっても、その文化と関連しているから1on1を導入して、うまく活用できている、ということが察せられた。
この本を読み直し、まとめることは非常に効果があると思う。 というのも、良い失敗経験がこの本には書かれており、どうすれば良い1on1ができるのかについてよく記述しているからである。
しかしながら、少し興味が1on1から逸れてきていること、 この本を読んで、会社における1on1をよりよくするための制度がまだ足りていない、ということを自覚したこと、 これら2点から、腰を据えて、まとめるのはまだ先でいいかな、と思うようになった。
あと、Team Geekのまとめの発表がまだ社内で終わっていないし、ネタを作成するのにまだ足りない感じがする。
team geek
このまとめについては、スライド形式にして、YouTube Liveとかで発表するとちょうどいいかもしれない。
next to read
次に読むのはデボラ・ザック『SINGLE TASK 一点集中術』にしよう。