"tech"

2024-11-04

ちょっと前からソフトウェア工学を触っている。興味から学んでいるというよりは必要に駆られて学んでいる側面が大きい。楽しい仕事をするためにつまらない状況を抑え込む力を身につけるために学んでいる。

とはいえ全くつまらないかというとそうでもなくて、ソフトウェアエンジニアやそれを取り巻く仕事はどんな体系で整理されているかを把握するのは職場の役割を整理して把握することにつながっていて面白みがある。

入門 コンピュータ科学 ITを支える技術と理論の基礎知識 (J.Glenn Brookshear)のソフトウェア工学の章を読んだ後に、ソフトウェア工学の基礎(玉井 哲雄)を読み進めている。

CSは学部の頃にある程度学んだが、その中で工学っぽい分野は触らなかったので学部レベルから勉強している。とはいえ実務経験やラボの先生のお話とかでソフトウェア工学に触れている(割とそれはそう)ので、全く素人って感じでもない。

ぼくが必要に駆られているのは要求工学なのかな。設計には純粋に興味がありそう。

2024-10-27

友達の結婚式に今度出席するので真面目に準備してみる。普段スーツを着ないので礼服を着るのはコスプレみたいでドキドキする。

  • 礼服が入るか検証
  • シャツを買う
  • ネクタイと胸につけるハンカチ買う
    • ネクタイの練習もしておかないとな
  • 靴を手入れする
  • ワックス買って練習する
  • 髪をいい感じに切ってもらうための店を見つける
    • 人に聞くのがいいかな
    • 2 or 3日に行こう(最近切ったばかりでできることあるのか?)
  • その他マナーを学んでおく

アプリケーションの開発・運用をしているとSQLのユーザをそれなりに作ることになる。データベースもしかり。それらをIaCな感じで管理したいがベストプラクティスをまだ知らない。

管理したいユーザの情報は以下の通り

  • ユーザ名(ホストを含む)
  • Grant
  • パスワード

簡単なのは、ユーザ名とパスワードだけ1Passとかで管理して、他は動いているものを見に行く方法。管理しない考え方。実態と齟齬がないことは良いことだが、設定を見るためには管理者権限が必要だしいちいち接続するのも面倒。また、複製が面倒なのも問題だし、設定の経緯をコメントに残したりバージョン管理したりできないので組織としてスケールしない。

Terraformで管理するのはいい線行きそう。ネックはパスワードかな。パスワードを平文で保持しないことを達成しようと思うと途端にややこしくなりそう。運用ではパスワードにシュッとアクセスしたいケースがあるため、他の解決策と併用するのが良いだろう。 Grantとユーザ名、変更の経緯の管理には向いていそう。

Terraformと1passを組み合わせるのが綺麗だろうと思った。ユーザ名は不変(変更したくなったら作り直す)にしておけば、色々いい感じになるんじゃないかな。

https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics が良さげ。 Refresh tokenをどこにどれくらいの期間保持するとか、どういうインターバルで無効化するとかで悩む。あとaccess tokenはauthorizationヘッダに突っ込むのが吉?とか。

ソフトウェア設計の指針をまとめた本で定番だけど日本語訳されてない(はず、2022年に買ったときはそうだった)。 APIを実装・設計したりそれに付随してコードレベルのモジュール(クラスとかで表現するようなレイヤ)を設計するときに役立つ指針をくれる。

僕がプログラミングのレビューをしたり、自分でプログラミングしたりするときに気にすることは割とここから学んだ(言語化しただけ?)と思う。インターネットでHTMLが公開されてたらどんなに嬉しいだろうと思う。レビューのときに「ここを読んでください」をできるので。

言語とかパラダイムに依存しない、プログラミング一般について使える知見が書かれているので繰り返し読む価値のあるものだと思うし、実際そうしている。以下のそれぞれのタイミングで読んだが、毎回楽しく思っている。

  1. がっつりプログラミング始める前
  2. 自分でコードを書くようになってから
  3. レビューをするようになってから

広くいろんな人に使われるAPIを設計するようになるとまた見える世界が違うのだろうと思う。

最近(日本語訳が)発売されったぽい本。内容的には流行り廃りがありそうな内容を扱っていて10年後には古くなっていそう。例えば第1章の「APIの設計・構築・仕様化」ではConnect使えばいいじゃないと思った。

とはいえこれまで10年くらいのプラクティスがおそらくいい感じに説明されていて、今どきのクラウドでいろんなサービスを動かして連携させるスタイルのアプリケーションをどうやって作っていくかを体系的に述べているように思う。ぼくはそのあたりを勉強中の身なので偉そうなことを言ったり評価をしたりできないのだけど、これまで断片的に学んで来たこと(そして腑に落としたり手を動かすに至らなかったこと)の使い所を自分の中で描けるようになっていると感じる。ほんまかいなと思うこともあるので、盲目的に信じるというよりは質の高い雑誌のような意識で読んでいる。

2024-10-26

  • aboutページの収取をするプラグインを実装して組み込んだ。あとはそれをいい感じに表示する必要がある
  • 今度人の結婚式に出るので身だしなみとか常識を身につける・髪切るとか服を用意する計画を立てる
    • 受付やるらしいのでちゃんとした方が良さそう
    • 礼服着れるか確認しておくか
  • helm完全に理解する。リリースとか意味わからん。installって何?kubectl applyとの関係は?

2024-10-10

  • protobufとかsqlcでファイル生成をするツールを使ってチーム開発をしているとすごくコンフリクトして辛い。生成するファイルを分割して、例えばrpcとかmessage単位にファイル(パッケージではない!)を分ければgitのコンフリクトは避けられる。パッケージも一緒なので振る舞いには影響しない。

2024-10-06

LLMはコンパイラとかみたいに説明とか分析を出力してくれるものではあるけど、 LLMはコンパイラよりも人間に近いものだと思っている。コンパイラみたいな決定的な出力をするツールに対して良い入力を与えてその出力をそのまま共有することには価値がたくさんあるけれど、 LLMから得られた出力をそのまま「LLMに聞いたらこう返してくれました!」っていうのは(少なくとも現代使えるLLMのレベルでは)意味が薄いと感じる。

人間に対して質問して、その回答をそのまま人に共有することにも、場合によって価値がたくさんあったり薄かったり感じることがそれぞれある。質問を回答してくれる人間に対して信頼というか専門家としての信頼というかがあったら、そのまま回答を知りたいと思うが、その辺のただの人とか単に知識がたくさんあるだけな人だと、 (アンケート回答のデータとかなら別だけど)意見や情報としては価値を見出しにくい。そんな感じに、ぼくはLLMを専門家だとはまだ思えていない。単に知識がたくさんあってそれっぽい文章を生成するだけの(論理的思考の欠けた)出力をするやつだと思う。

とはいえ知識や経験がたくさんあれば結構な量の論理的思考は不要だろうことは段々わかってきた。なんのために考え事が必要なんだろうね。そして論理的思考とは何なのだろう。

今週は疲れた。先週の金曜から毎日飲み会だとか人と会ったりだとかのイベントがあった。それぞれは楽しいのだけど全てに参加していると大変。昨日はずっと寝ていたし、今日は家事をしていた。本を読む気力もない。体としては寝ても良さそうなのだが頭は何かをしたがっているので文章を書いている。本を読みたい気持ちもあるが、落ち着いて考え事をしたい気持ちもある。今その本を本当に読みたいのだったか、とか。

わかったつもり 読解力がつかない本当の原因 (光文社新書) に本屋で出会って読んでいるのだが良い。わかるとか理解する、みたいなことは一体何なのかは高校生の頃からのぼくのテーマの一つなのだが、それを一段深めてくれている。

ぼくの中での「理解する」とは、説明をつけることとか腹落ちしていることであった。論理とかは客観的なアレとして社会的に認められていたり、自然科学は実際問題役に立っているので市民権を得ているが、そんなことは「理解している」とは関係ないと思っている。理解しているか否かは主観的な問題で、腹に落ちた感じがするなら自分はそれを理解していると思うし、自分が同意できる説明を他者がするなら他者はそれを理解しているように感じる。そういうものだと思っていたし、今も思っている。

この本の説明ではぼくの解釈と矛盾しない中で理解の程度を論じているように思う。文脈とそれに対する解釈を持っている人間は、文脈を新たに獲得し明らかにすることで対象の解釈をより鮮明にする、みたいな主張だと今のぼくは大体思っているはず。鮮明にするというか、よりわかるというか。

これまでのぼくの理解への価値観には抽象度の違いがなかった。抽象解釈をするときにどれだけfineに解釈するかの違いが認識する文脈の違いに依存することをこの本に解らさられた。

この前ご近所さんとお話した影響で今日は八百屋に行ってきた。はじめて行くタイプの八百屋で、なんとカゴとレジは存在しなくて、床に陳列されている野菜を見ながら店員さんに口頭で欲しい野菜をクエリするタイプの買い方だった。ちなみに野菜の品質はそんなに良くなかったので次は他のところかなと思っている。安くはあった。

結局人は自分と近しい考えを読んでそれを楽しいと思うのだな、みたいなことを恩師が言っていたのを思い出した。ぼくもそう思う。そういう答え合わせみたいな読書は楽しい。

読書に限らずおしゃべりとかでもなんやかんや同調とか、似たような哲学のもとでの「議論」みたいなことをするときが楽しそう。「あいつはやばいから!」と嬉しそうに友達を紹介する人は、大体その友達と大差ないとかだとか。議論をするときに背景に共通点を見出して群れるのもそういうことだと思う。良し悪しは知らない。

named-letです。

2024-09-16

  • 掃除
    • ルンバを起動したのでok
  • 外出
    • 電車乗るくらいの外出をする。秋物出たかな。あるいは外で使うと幸せになれるグッツを買うか。
    • ランニングパンツと靴下を買う。帰省でランニングのズボンを置いてきたのと、靴下が大体ボロボロになってきたので。
    • 靴下は買った。ランニングパンツはまあいっかと思って買わず。そのほかに秋に向けて服を見たけどピンと来なかったので特に買わずだった。
  • 本読む。k8sのあれ。あとは認証の技術気になるので学ぶ。認可も気になる。
  • todoをリストアップする拡張の実装
  • todoの拡張、出先でチェック入れたくなりそうなので、githubでの編集へのリンクをつけたい
    • やっぱりいいや。出先ではのんびりしよう。todoのことなんて忘れればいい。

https://diary.nfurudono.com/todos/に実装した。これでもう過去のtodoを忘れない。収集とレンダリングの両方が必要でだるかった。特にレンダリングはunifiedのアーキテクチャを理解してなくて手間取った。今の実装がunifiedのアーキテクチャに沿っているか自信がない。

本棚を作って設置したところ、そろそろキャパシティが限界だと気がついた。本棚を増やすためには引越しが必要。そろそろ減らしてもいい本も増えてきたので、 2年周期の引越しで問題ないとは思うが。今で3/4年か…、今年のうちに西側の探索をしたいな。今度友達とどこに行くか決めてないので、そっちの方に雑に行ってみて案内してもらおう。向こうが詳しいかは知らないけど。

寝たり本を読んだり景色をみたり、考え事をしたりする環境として電車で過ごすのが好き。年末は北国に電車に乗りに行きたいな。高校生の頃に一週間電車に乗りっぱなしの旅行をしたけど、あんな感じのことをまたやりたい。それでいうとシベリア鉄道は憧れる。

景色が変わるのがいいし、椅子しかないのも良い。なので新幹線みたいな机があるのはそれほど好きじゃない。横に細いサイドテーブルみたいなのはok。ものを置けるけどそこで何かやる感じではないのがいい。集中できるし、パッと休憩しようと思ったら外を見ればいい。なので電車に乗るのは日中がいい。夜は外が見えないので興醒めする。

家にいても景色が変わらなくてつまらない。外に出るのも良いが、それだと本読んだりできない。電車の中は家と同様に自分が暇なのに快適で、移動しているのがいい。

金曜日の昼過ぎに三連休だということを知った。なんと来週も三連休だということだった。この三連休は本棚を作り、あとは家でまったりした。こういうのもあり。

Goのanalysisとtypesに入門する

Goで静的解析してリンターを実装したい。具体的には、あるT1インターフェース型の変数がスコープにあるときは、T1よりゆるい任意の型の使用を禁止する、みたいな制約を入れたい。その辺に転がっている記事ではASTを覗いてみたり、SSAを覗いてみたりするようだけど、ASTとその型をまともに扱っていつつ、いい感じに静的解析ツールとして仕上げる記事を見つけられなかった。

この記事ではGoプログラムの静的解析ツールを実装するために存在する標準的なツールチェーンの思想を説明する。Go Analyzerは静的解析ツールフレームワークとして用いる。具体的な静的解析には標準ライブラリを用いる。

具体的には、あるT1インターフェース型の変数がスコープにあるときは、T1よりゆるい任意の型の使用を禁止する、みたいな制約を入れたい。

これを検証するGoの静的解析ツール。例えば以下のようなrの使用を検知したい。

func parse(r io.Reader) (string, error) { ... }

func (rw io.ReadWriter) {
	var r io.Reader = getReader()
	s, err := dump(r) // 「rじゃなくてrwを使ってくれ〜!」と指摘したい。
	...
}

https://pkg.go.dev/golang.org/x/tools/go/analysis これ。準標準なパッケージ。ドキュメントの冒頭に思想がちゃんと書かれているのでそれを読むのが良さそう。

一個の解析ツールに対応する。Analyzer.Runに解析を実行する関数を定義する。この解析ツールを実行するとき(実行するのはフレームワークの仕事)に、Pass構造体が渡される。

Pass構造体は解析対象のパッケージごとに作成される。なので解析の単位はパッケージごとということになりそう。いいじゃん。

type Pass struct {
	Fset         *token.FileSet
	Files        []*ast.File
	OtherFiles   []string
	IgnoredFiles []string
	Pkg          *types.Package
	TypesInfo    *types.Info
	ResultOf     map[*Analyzer]interface{}
	Report       func(Diagnostic)
	...
}

こいつを通じて解析をする関数は処理対象のデータにアクセスしたり、処理結果を報告したりするぽい。モナドとか代数的エフェクトみたいで綺麗だ。そう思うとあれらは抽象化された一つの振る舞いの切り口を表現するための基本的な演算を定義していたのだから、まあそうだなと思える。Kokaで静的解析ツールを作るときにはpassエフェクトを定義するのだろう。

The Fset, Files, Pkg, and TypesInfo fields provide the syntax trees, type information, and source positions for a single package of Go code.

これは本質情報の予感。このあたりにうまくアクセスすることで、ぼくたちの頭の中で想像する型付き抽象構文木へのアクセスを実現できるんだろう。データ構造が思ったのと違いそうなことには気をつけよう。

これらに加えて、他のanalyzerが出力してくれる結果をこのanalyzerの入力として使える。それにアクセスするためには pass.ResultOf[a].(aResType)を参照すればよい。

診断(diagnostics)を出したければPass.Reportとか、パッケージで提供されているReportfとかを使うらしい。

ここまでで、モジュラーに静的解析ツールを実装するフレームワークの構造がわかった。それに乗っかれば静的解析をいい感じに動かすことはできそうだ。静的解析の処理を実装する方法もなんとなくわかった。Pass構造体の世界観に乗っかればokな感じがする。

次に自在にプログラムを解釈する方法を知りたい。プログラムはコンパイラに処理されていろんな形態に変換されるので、ユースケースに応じて適切な表現を選ぶ必要がある。今回は型付き抽象構文木を扱いたいので、Pass構造体のFset, Files, Pkg, TypesInfoあたりを上手に使えると良さそうだ。特にTypesInfoが気になる。これは types.Info型をとるみたいなので、typesパッケージを見に行く。

typesパッケージはこれ https://pkg.go.dev/go/types。冒頭の説明がスッキリしていてまだ何をやれば型付き抽象構文木に対してクエリっぽいことをできるか、どんなクエリっぽいことが許されるかを理解できない。なので貼ってあったチュートリアルのリンクを辿る。なお、スッキリしている説明自体は読んでよかった。このパッケージが扱うフェーズで何をやるか説明されていて、もっと詳しく読んで良さそうなことに自信を持てた。

なお、僕の目的のためには他の解析ツールの結果を使う方が良いかもしれないとも思う。暇だし気になるのでチュートリアルを読むのに時間をかけるけど。

脱線したがチュートリアルを読み進める。https://go.dev/s/types-tutorial これ。これを読む目的は、何をやれば型付き抽象構文木に対してクエリっぽいことをできるか、どんなクエリっぽいことが許されるかを理解すること。

このチュートリアルはジェネリクスには対応してないらしい。ジェネリクスのためのドキュメントは別途あるとのことだけど、今回は基礎を知りたいので気にしない。

イントロと例くらいは読んでみて、あとは斜め読みでいいかな。まずはイントロ。

Measured by lines of code and by API surface area, it is one of the most complex packages in Go’s standard library, and using it requires a firm grasp of the structure of Go programs.

とのこと。大変だ。

Starting at the bottom, the go/token package defines the lexical tokens of Go. The go/scanner package tokenizes an input stream and records file position information for use in diagnostics or for file surgery in a refactoring tool. The go/ast package defines the data types of the abstract syntax tree (AST). The go/parser package provides a robust recursive-descent parser that constructs the AST. And go/constant provides representations and arithmetic operations for the values of compile-time constant expressions, as we’ll see in Constants.

データ構造とアルゴリズムを分けるの賢そう。parserにastを定義しないとか偉い感じがする。色々あるんだろうな。どう嬉しいのかはわからないけど。定数畳み込みをastに対して実装したいが、parserに依存するわけではないよね、みたいな話かな。

名前解決、型検査、定数式の計算は一緒にやらないといけないなるほど。ここでいう名前解決とは、名前の出現に対してその宣言を対応させること。

例まで読んだがパッケージレベルの話しかわからないな。ぼくは式とかのレベルでプログラムを処理したいんだ!ということで本命のInfo構造体への言及を探すことにすると、TypeAndValueでそれらしいことを述べている。

Info.Typesは map[ast.Expr]TypeAndValue らしい。そろそろ手を動かして、プログラムのこの要素は式として扱われるか?とかをみたい。と思ったらドキュメントが例を出してくれた。こういうときが一番楽しい。式があったら型は得られるようになってるのね。ただまだよくわかってなくて、mapの定義域をast.Exprとしているが、そのExprとして本当に登録されるのはどの範囲のExprなのかがわからない。当然 ast.Expr{} なんて渡しても、その型を計算しているわけがない。どういう操作で手に入れたast.Exprに対しては、Info.Typeがその型を教えてくれるんだろうか。Infoを生成するやつが知ってるのかな。analysisパッケージはよくわからんPassがInfoを持っていたので微妙だけど、パッケージの単位で処理をするのでパッケージに存在するすべての式の型を教えてくれると思って良さそう?

確かにConfig.Checkはパッケージを型検査して、引数にInfoへのポインタをとって結果を書き込みそう。

次に、型同士の比較をしたい。具体的には、T1が必要な文脈でT2は使えるか (assignable) を判定する方法が欲しい。そのためにこれが使えるhttps://pkg.go.dev/go/types#AssignableTo。引数に渡すTypeインターフェースの値はTypeAndValueで取れるので、ほとんど勝ったようなもの。ちなみに僕は、最初ConvertibleToを使っていて全然ダメだった。ConvertibleToは数値が変換できるか判定するやつぽい。

2024-08-15

日記をnextjsでビルドして、cloudflare pagesにデプロイするようにした。cnameの設定が効くようになれば、https://diary.nfurudono.comから見えるようになるはず。

cloudflareのアカウントを初めて作って設定したが、体験よかった。デプロイとか周りの開発のためにCLIツールやそれのgithub actionsバインディングが提供されていて、サクッとデプロイできた。記念すべき初デプロイの成功をメモしておくhttps://github.com/naoyafurudono/naoyafurudono.github.io/actions/runs/10399555684/job/28798614059

Hugoの設定をたくさん書いていても楽しくないのでNext.jsでなんでもやってみよう、というモチベーション。unifiedがいい感じで楽しいので動くところまで持って来れた。

ソースコードはhttps://github.com/naoyafurudono/naoyafurudono.github.io/tree/main/tools/ttにある。

2024-08-03

ソフトウェアを設計するときにはどこを変えやすくしたいか(どんな変更をしやすくしたいか)を把握したい。 Expression probremは必ずしも解決しなくてよいと思っていて、変更に必要な気合がどれくらいかを把握したうえでそれを許容できるかが論点だと思う。

もちろん使う気合が小さいのに越したことはないのだが、コード読み書きするのはみんな好きだろうし、嫌いなひとは割とAIに任せられる世の中なのだから、小手先のテクニックでなんでもできる設計とかにしておくうまみはあまりないと思う。

会社ではmacbook proを使っていて、家ではmacbook airを使っている。使っているソフトウェアとか設定は大体同じにできていて便利ではあるのだけど、今日は手ぐせで会社でよく触っているリポジトリにcdしようとして失敗するのを何回もやってしまった。 lsのノリでそのディレクトリにcdすることに辛さを感じる。

  • 飲み会の場所を抑える
    • ビールをたくさん飲めるところでそう遠くないところがいい
  • 健康料理
    • 野菜を食べたいです
  • 外出
    • 15:30を回ったが、まだ外に出ていない。お日様が欲しい
  • 洗濯
    • あとは干すだけ
  • 運動
  • ルータを吊るす
    • そういえば家の壁に釘打っても怒られなさそうな板が壁に付いているので、そこにルータをなんとかつけたい

今日は小学校4年生の頃に転校してきた友達の誕生日。ブルーアイズホワイトドラゴンをくれた、寡黙なやつだった。元気だといいな。

AHK入門

Windowsマシンでキーボード操作が不便なので導入する。悪態をつきながらも使っている人を知っているので内容を理解していないが期待している。

https://www.autohotkey.com/ 公式ページからバイナリを落とせる。インストールするとwelcome画面が開いたのだが、そこに「コンパイルする」ボタンがあって、ちょっと不安になる。僕はプログラムをボタンを押してコンパイルしないといけない?

ついてきたマニュアルはいい感じのスタイリングでよみやすそう?

頭から飽きるまで読んでいく。

  • スクリプトの作成 (Create a Script)
    • Be sure to save the file as UTF-8 with BOM if it will contain non-ASCII characters. For details, see the FAQ.

    • BOMがいるらしい。そういえばBOMってなんなのだろう。結局まだちゃんと理解してない。
  • スクリプトの実行 (Run a Script)
    • なんかソースファイルをダブルクリックしたりして実行できて、実行してる間だけ効くらしい。
    • イベントハンドラみたいなやつの定義がそれぞれのスクリプトに対応するかと思っていたが、なんかメンタルモデルがあってなさそう
  • それぞれのスクリプト実行がWindowsのトレイアイコンに反映されるらしい。なるほど

飽きたのでhello worldする。

以下はCapsLockを押すとhello, worldと出力するよう設定するahkスクリプト。ちなみにこれらのhello, worldはCapsLockを打って入力している。

#Requires AutoHotkey >=v2.0.0

CapsLock::
  {
    SendInput "hello, world"
  }
  Return

CapsLockで英数変換するのは以下で実現できた。

#Requires AutoHotkey >=v2.0.0

CapsLock::
  {
    SendInput "^{Space}"
  }
  Return

紆余曲折あって、以下のようになった。Windowsでもいい感じにvim使えるようになって幸せ。

https://github.com/naoyafurudono/dotfiles/blob/main/autohotkey.ahk

#Requires AutoHotkey >=v2.0.0

IME_SET(SetSts, WinTitle:="A")    {
    hwnd := WinExist(WinTitle)
    if  (WinActive(WinTitle))   {
        ptrSize := !A_PtrSize ? 4 : A_PtrSize
        cbSize := 4+4+(PtrSize*6)+16
        stGTI := Buffer(cbSize,0)
        NumPut("Uint", cbSize, stGTI.Ptr,0)   ;   DWORD   cbSize;
        hwnd := DllCall("GetGUIThreadInfo", "Uint",0, "Uint",stGTI.Ptr)
                 ? NumGet(stGTI.Ptr,8+PtrSize,"Uint") : hwnd
    }
    return DllCall("SendMessage"
          , "UInt", DllCall("imm32\ImmGetDefaultIMEWnd", "Uint",hwnd)
          , "UInt", 0x0283  ;Message : WM_IME_CONTROL
          ,  "Int", 0x006   ;wParam  : IMC_SETOPENSTATUS
          ,  "Int", SetSts) ;lParam  : 0 or 1
}

IME_GET(WinTitle:="A")  {
    hwnd := WinExist(WinTitle)
    if  (WinActive(WinTitle))   {
        ptrSize := !A_PtrSize ? 4 : A_PtrSize
        cbSize := 4+4+(PtrSize*6)+16
        stGTI := Buffer(cbSize,0)
        NumPut("DWORD", cbSize, stGTI.Ptr,0)   ;   DWORD   cbSize;
        hwnd := DllCall("GetGUIThreadInfo", "Uint",0, "Uint", stGTI.Ptr)
                 ? NumGet(stGTI.Ptr,8+PtrSize,"Uint") : hwnd
    }
    return DllCall("SendMessage"
          , "UInt", DllCall("imm32\ImmGetDefaultIMEWnd", "Uint",hwnd)
          , "UInt", 0x0283  ;Message : WM_IME_CONTROL
          ,  "Int", 0x0005  ;wParam  : IMC_GETOPENSTATUS
          ,  "Int", 0)      ;lParam  : 0
}

IME_TOGGLE() {
  current := IME_GET()
  IME_SET(!current)
}

IME_OFF() {
  IME_SET(0)
}

CapsLock::
  {
    IME_TOGGLE()
  }

~Esc::
  {
    IME_OFF()
  }

認可に入門 wip

https://www.osohq.com/academy これを読んで認可に入門します。頑張るぞ〜!

https://www.osohq.com/academy/authorization-academy

Chapter II: What authorization is: how to organize your authorization code Chapter III: Role-based access control: grouping permissions in your app into roles like User and Admin Chapter IV: Relationship-based control: grouping permissions by relationship, like “the creator of a post may edit that post” Chapter V: Authorization enforcement: once your app has decided to allow or deny access, what do you do with that decision?

こんな感じとのこと。色々あるんだな。どれも気になるが、特にアプリケーションコードにどうやって統合していくかが気になるところかな。もれなく頑張らずに実現したい。

https://www.osohq.com/academy/what-is-authorization

具体例を挙げてWebアプリケーションにはレイヤがあって、それぞれのレイヤではどんな情報を取れて、どんな認可ができるかを議論する。

また、“4. Adding Authorization to an Application>”ではコードでの認可処理の書き方を比較する。

Naiveなアプローチだと以下のつらみがあると言っている。それな〜。

That quickly gets difficult. As the number of places where you need to apply authorization increases, you end up duplicating the same logic. Making any change then requires us to remember every place our logic is duplicated.

どうしたらいいんだ…

Formalizing Our Authorization Model なるほどね(以下を認識する)。

  • actor
  • action
  • resource

UNIXのファイルにつけるパーミッションもこの考えで整理されてそう。どのユーザがどのファイルに対してどんな操作をするかを気にして権限の管理をしてるイメージ。

グループIDみたいなのはactorを発展させたものぽい。 sudoもその辺をいじるのかな。Capabilityはactionsの部分かな。それだけでもなさそうか。

上の三つ組を考えるメリットは二つあるとのこと。

  • 言語を共有できる
  • 設計としてシンプル

設計がシンプルと言ってるのは、以下のように認可のインターフェイスを持てそうということらしい。

isAllowed:: (Actor, Action, Resource) -> Bool

こういうインターフェースを定めることで認可の周りで責務の境界を定められる。呼び出し側の責務にenforcement, 呼ばれる側の責務にdicisionという名前をここではつけている。

認可処理の結果をもとに何をするかを決めること。そもそも認可処理の呼び出しをするのもここの範囲だし、その結果アクセスがなければ403返すとかするのもここ。良いかどうかを気にしつつ、その結果どうするかを決めるのがここ。

基本はyes/noを返すやつ。さっきの関数の実装。警告とかは出したきゃ出せばいい。純粋である必要はなさそう。

5. Putting Everything Together がまとめだった。ここまでのメモが集約されてる感じ。

あとここには書かなかったけど、enforcementとかdicisionとかの話の後にenforcementをどこに実装する?みたいな話があるがマイクロサービスぽいアプリケーションを書いてないとそもそも問題にならなさそうで、一旦そこに僕は興味ないのでスルー。

アーキテクチャの話はなるほどって感じだが、まだ考えられることはたくさんある。

  • 権限が足りないときのエラーメッセージの返し方
    • 足りない場合は403だけじゃなくて何を足せば良いか知りたいとか
  • 管理者にアプリユーザがどんな権限を持ってるかを表示するとか
  • グループとか

https://www.osohq.com/academy/role-based-access-control-rbac

半開閉区間

コンピュータで区間処理するときは半開閉区間で持つことが多い気がしている。もはや信仰のレベルで身についているので自分一人で決めて終わりなときはそれで良いのだが、説明が必要なときに困る。そのときのために良さげな参照を集めておく。

何というか区間は連続な集合の2端点を指定して定まる部分集合であって、その全体からなる集合族を扱おうと思うと半開閉区間にしておくと綺麗というのも関係する?

区間は全順序集合の部分集合で、それらを体系的に考えようと思うと区間の集合の性質を考えるのが良いはず。つまり区間からなる族を考えると良さそう。

考える全順序集合が連続な集合なら、半開閉区間からなる族を考えると、任意の区間は有限個の区間の非交和として表現できる半開では無い区間の族ではこの性質は成り立たなさそう。漏れとダブりがないように区間を分割する必要は実用的に割とあってそれをきれいにできるのは半開閉区間だけということになる。

ググってみると集合半環という概念があるみたいで、それにこの性質が効いてるぽい。集合半環 (wikipedia)をみると良さそう。

むずい。

https://chatgpt.com/share/4c778bf6-f43a-4230-825d-398ad025a457

結構良い回答をもらえた。

プログラミングで区間を表現する際に半開閉区間(半開区間、片開区間とも言う)を用いると良い理由は、特に次のような点にあります:

  1. 直感的なインデックス操作:

    • 配列やリストなどのデータ構造において、インデックスは通常0から始まります。半開閉区間 [start, end) を使うと、start から end-1 までのインデックスが含まれるため、範囲を扱う際に計算がシンプルになります。例えば、要素数が10の配列に対して [0, 10) という範囲を指定すると、全ての要素を含むことになります。
  2. 区間の連結が容易:

    • 半開閉区間は連結する際に便利です。例えば、 [start1, end1)[start2, end2) という2つの区間を連結する場合、end1start2 が同じであれば、それらを連結して [start1, end2) とすることができます。このように、区間の端点が明確に分かれているため、エッジケースが少なくなります。
  3. 境界の一貫性:

    • 境界条件を処理する際、開区間の端点は含まれないため、範囲外アクセスのリスクが減少します。これにより、特にループ処理や再帰的なアルゴリズムの実装が一貫しやすくなります。
  4. 数学的な整合性:

    • 半開閉区間の表現は、数学的にも広く使われており、理論的な背景からも自然な表現です。例えば、集合の分割や区間の分割などで、一貫した扱いが可能です。
  5. プログラミング言語のサポート:

    • 多くのプログラミング言語やライブラリが、半開閉区間をデフォルトでサポートしています。例えば、Pythonのリストスライスや、C++の標準ライブラリの範囲は、半開閉区間の形式を採用しています。このため、言語やライブラリの機能を活用する上で半開閉区間を使うのが自然です。

以上の理由から、プログラミングにおいて区間を表現する際には半開閉区間を用いることが一般的であり、推奨されます。

数学的な観点から見て、半開閉区間(例えば ([a, b)))を使用することにはいくつかの重要な性質があります。これらの性質により、一貫した扱いや直感的な操作が可能となります。以下にいくつかの重要な性質を挙げます:

  1. 区間の連結性:

    • 2つの半開閉区間 ([a, b)) と ([b, c)) を連結すると、新しい半開閉区間 ([a, c)) を得ます。これにより、連続する区間を簡単に扱うことができます。
    • 例: ([1, 3)) と ([3, 5)) の連結は ([1, 5)) となります。
  2. 区間の分割性:

    • 半開閉区間 ([a, c)) を点 (b) で分割すると、2つの区間 ([a, b)) と ([b, c)) になります。このように、区間を分割する際の扱いがシンプルです。
    • 例: ([2, 7)) を (5) で分割すると ([2, 5)) と ([5, 7)) になります。
  3. 一意性と包含関係:

    • 各点は1つの半開閉区間に一意的に属します。具体的には、点 (x) が区間 ([a, b)) に属するのは (a \leq x < b) の場合のみです。このため、区間の包含関係を判断するのが容易です。
    • 例: (x = 3) は ([1, 5)) に含まれますが、([3, 7)) にも含まれます。
  4. 空集合の扱い:

    • 半開閉区間において、区間 ([a, a)) は空集合となります。これにより、区間のサイズが負になることを避け、理論的な一貫性を保ちます。
    • 例: ([4, 4)) は空集合として扱います。
  5. 順序性と計算の簡便性:

    • 半開閉区間は順序を持っているため、数直線上の位置関係を直感的に理解できます。これにより、範囲の計算や比較が簡単になります。
    • 例: ([2, 5)) と ([5, 8)) の関係は明確に非重複であると分かります。
  6. 測度論との整合性:

    • 測度論(特にルベーグ測度)においても、半開閉区間は重要です。半開閉区間は測度が容易であり、特に区間の長さが (b - a) で計算できるため、実際の応用において便利です。

これらの性質により、半開閉区間は数学的に一貫した扱いが可能となり、プログラミングにおいても同様の利便性が得られます。このため、アルゴリズムやデータ構造の設計において半開閉区間を使用することが推奨されます。

閉じたとこから開いたと〜こ!

好き好き大好き〜

RubyKaigi2024参加メモ

RubyKaigi2024に参加したので、思ったことをメモしておきます。

参加したセッションはこちら: https://rubykaigi.smarthr.co.jp/2024/plans/d2350276-c631-4bdc-ad75-49e446e798a3

今回のセッションをいくつか聞いてShopifyのやり方に憧れるようになった。エンジニアリングをしていく上での姿勢として、課題に対して上流から対処しよう、みたいな箴言があってそれが心に残っている。 ShopifyのRuby周りのチームはまさにそれを地で行っていると今回のセッションを聞いて感じたそういうチームに所属して(作って?)良いエンジニアリングをしていきたいと思っていたのだが、これまでは具体的なイメージいを持っていなかった。

ShopifyのRubyチームによる貢献にはすでに自分が直接的に恩恵を受けているし、彼らがどういう思想で取り組んで具体的に何をしてきたか、これからどういう思想でやっていくかを生で聞くことができた。遠いけれども具体的に目標とする存在に出会えたことが今回の一番の収穫だったと思う。

バージョンとかライブラリのインストールとか大変だしよく分からないのでスッキリする方向に進んでいきそうで楽しみ。セッションも普通に勉強になった。

一方的に知っていた人もお互い初めましてな人もお話しできてよかった。今回存在を新たに認知した人ももちろんいて、いろんな人が色々やっていることとか、意外とコミッタ少ないこととか認知できて良い。 Rubyって人間が作ってるんだなと感じる。

現実味を感じる一週間でした。

ElmアーキテクチャをReactで実現する話

リアクティブプログラミングの勉強をしていた頃にElm言語を知って好きになった(全然コード書いてないけど)。特徴はElmアーキテクチャにあると思っている。 Webアプリケーションの大体のフロントエンドアプリケーションはこう言うアーキテクチャで表現できるはず、みたいなことを言っていて、そのアーキテクチャが簡単なので気に入ったのだろう。

ユーザやAPIとやりとりをするアプリケーションなので、外界からの入力は当然ある。

また、それによって(のみ)アプリケーションの状態は変化する。アプリケーションが取りうる状態はアプリケーションに固有だし、どんなことがアプリケーションで起こって(入力としておきえて)、その結果どのような状態遷移をするかもアプリケーションに固有。なのでそれらはアプリケーションの実装者が決める。入力というかイベントがあって、それによってある状態から他の状態に遷移する、状態遷移系を定義するのはシンプルに思える。

状態が決まればそれの描画結果も決まるはず。もちろんDOMとかスタイルを当てたりとかして状態を描画結果に対応づける方法はそのアプリを作る人が定義する。描画というのは状態から描画結果への写像なのだ、と思うのがシンプルなポイント。

最初にあげた、外界からの入力は曲者。クリックとかレンダリングとかAPIの呼び出しとかは、知ったことではない感じがする。少なくともフロントエンドアプリケーションの範囲で意味を定義して実装するものではない。なのでその辺はElmのランタイムがいい感じに実装してインターフェイスを提供してくれる。そのインターフェイスを使いつつ、イベントを定義することになる。

Elmアーキテクチャは最高なんだけど、仕事のプロジェクトで使うとなると言語の選択はもっと資本主義ぽい判断が必要になって、TypeScriptとReact使うかという気持ちになる。

幸いなことにこれら二つでElmっぽいことはできるので、今の仕事では黙々とそれを進めている。 Reactで違うところは、Elmランタイムがなくてもうちょっと小さな部品がたくさんあって、それをいい感じに組み合わせて使うところだと思う。useEffect で頑張るとか。

そのあたりを頑張っているうちとかに、だんだんElmアーキテクチャっぽくするのが辛くなったりして辛い。みんなで強い気持ちでその方針に向かうのが良さそう。

https://guide.elm-lang.org/ がElmのガイドでElmアーキテクチャを推してくれる。なのでみんな読んでほしい。

エフェクトハンドラで実現したい世界と、Elmアーキテクチャみたいな世界は重なる部分が多そうだと感じている。 Reactの開発者もuseContextはalgebraic effectなんだ!みたいなことを何処かで言っていた気もするし、誰しも思うことなんだろう。

2024-03-26

イベントソーシング?と言うのかわからないけど、イベントを全部持っておけば現時点での状態はイベントを全部みて計算できるので永続化しなくて良くない?みたいな考え方がある(はず)。

イベントを解釈する遷移規則が変わらなければそうだけど、実際のソフトウェアではプログラムは継続的に変わっていくもので、イベントの解釈が変わらないこと(もっと言えば解釈できること)を保つのは大変そう。検証するためにリグレッションテストみたいにスナップショットを取っておいて、遷移規則が変わるたびに新しい解釈結果と比較すれば良いかもしれないw。

世間ではその辺どうしているんだろう。遷移規則が変わらない範囲でこのアーキテクチャを採用することでクリアしてるのか、そんなことは気にしないのか(あるいは気にならないのか)、他に上手いやり方があるのか。

このアーキテクチャを採用する目的にもよるか。

Nextjsのプロジェクトにstorybookを導入してみた

https://github.com/naoyafurudono/timer/pull/1

このプルリクエストで頑張った。コミットメッセージにやったことは書いてある。

公式ドキュメントがしっかりしてそう。storybookが内部で使っているwebpackが@ インポートを読めないみたいで、プラグインを入れる必要があった。

2024-03-20

Webアプリケーションのテストをどう実施したものかと最近考えることが多い。 Webアプリは雰囲気で変更したいはずで(ソフトウェアって大体そう?)、またテストは長持ちしてほしいと思う。

テストではなんらかの仮定のもとで実装がある条件を満たすことを検証する。その仮定を上手に置くことがテスト戦略を決める人の腕の見せどころだろう。

例えば関数の単体テストをする場合は、そこに渡す実引数を仮定して、その関数の出力が意図した通りになることを検証するし、モックを使うならそのモック対象の振る舞いを仮定することになる。 e2eではユーザの操作を仮定するのだろう。

いろんな仮定の置き方とその結果実現できる検証内容がある気がしていて、安定した仮定(覆るとテストを直さないといけない)を選びつつ、そこがクリアできれば安心と思える検証内容を取ることがテスト戦略の設計で目指すことなのだと朝の東横線で思ったのだった。

で、そういうお得さを出せるように実装するのも大事なんだろうなと思っています。

2024-03-09

フロントエンドのモデルとRPCについて考えてみたい。

Webアプリケーションのフロントエンドがリッチなときに、テストをどんな感じで書こうかとか、そもそもアプリケーションをどんな感じで書こうかと悩む。僕は悩んでいる。

ユーザとページがあって、必要に応じてAPIを呼ぶ、その結果画面遷移が起きるくらいのものだったのが、しっちゃかめっちゃかしてきてそれを理解できるのはコードを書いた時空にいる人のみになる。

フロントエンド、副作用が多すぎるんだよな。レンダリング、人間、apiが絶対にいるのでそれは大変に決まっている。ログを気軽に残せないとか、エラーの出し方に気を使うのも辛い。Webアプリのバックエンドなら、しょうがないからログたくさん出して500返しとくかができるけど、フロントエンドで想定外が起きたときに、すまん壊れただけでは完結しない。

そもそも完結しないようなレイヤ分けが間違ってるのか?ネットワークの隔たりとレイヤ分割が一致してしまっているが、フロントエンドアプリケーションも気軽に壊れさせてあげてほしい。その内容をログに取ったりユーザに幸せになってもらうためのあれこれは他のレイヤでやるべきなんじゃないかと思ったりしました。

今お酒を飲んでいるし、今日会社で上司というか先輩というかがウイスキー好きだとしって酒モチベが高い。最悪だな。

お酒を楽しく飲める会をしたいね。酒の好きなところを語ると良さそうに感じたのでやります。

まずいやつはまずいけど、美味しいやつは本当に美味しい。他の食べ物と同じで体調とか好みによるのだけど、摂取するもので酒が一番美味しいことはままある。ウイスキーとビールは特にそう感じる。日本酒とかワインはそんなに美味しくないと思います。

アルコールを摂取するといわゆる常識を司る理性が外れて、あらゆる人と小学校の友達のように接することができるようになって楽しい。それっぽい言い方をした(?)けど、僕が小学生みたいな動きをしてるだけかも。

あと音楽聴くときにはアルコール入ってるともっと楽しめて好き。

インカレの1,2週間前くらいな感じがして楽しい。フルタイムで専門目な領域なのが痺れる。

2024-02-17

glangにgeneraterを入れようというプロポーザルがあって、試験的に実装されているみたい。いくつかのパターンがあるけど、だいたいこんな感じで使える (The Go Playground)

ジェネレータとして使われる関数は定義の段階では普通の関数と区別がつかないような構文定義をされている。コンパイラやランタイムの実装が気になるし、静的解析ツールが大変なことにならないかが心配。

気が向いたらプロポーザルを読もう。ジェネレータが引数にとる関数がブールを返すけど、どちらを返すかを誰が決めているかも気になる。

第一印象ではgolangには入らないで欲しいなと感じた。

2024-02-13

今日1on1で教えてもらった。ロールモデルとして追っていく。https://scrapbox.io/kawasima/%E3%82%A4%E3%83%9F%E3%83%A5%E3%83%BC%E3%82%BF%E3%83%96%E3%83%AB%E3%83%87%E3%83%BC%E3%82%BF%E3%83%A2%E3%83%87%E3%83%AB

2024-02-12

管理画面の設計について考えてみる。 Webアプリケーションでもろもろを設定する際のUI設計を考えている。

設定の初期化時や更新時でフローが異なるはずだ。

初期化のタイミングでは、氏名やメールアドレスの設定・認証や、オプショナルな事項(決済情報とか追加の契約事項とか)の設定が挟まり、最後に確認してよければコミット、ダメなら修正する。

更新では最初の設定で気に食わなかったところを修正したり、追加の設定項目をいじったりするだろう。

それぞれのタイミングで何を設定させるかや、どれだけサクサク入力できるかによってユーザの体験が左右されそう。例えば初期では認証情報だけをコミットして、その他の情報は更新で登録する手もあれば、ファストバスを登録時に持ってきてしまって、8割のユーザが最短で使用を開始できるようにするパターンもあるだろう。

ユーザが行うそれぞれのフローはアプリケーションというかシステムにどのような影響を与えるだろうか。というよりも、ユーザがそれぞれのフローの結果及ぼせる作用をどのようにデザインすると良いだろうか。

この作用をデザインするにあたって、アプリケーションで表現するモデルがどんなであるかを明らかにしておくと良いはずで、そのモデルに対する作用の一つの実現方法としてユーザが操作するフローがある、と思えそう。

ユーザによる操作じゃない作用としては、決済が行われたとか権限が時間経過で失効したみたいな作用がありそう。

データにもいろいろありそう。モデルを表現するためのデータと、作用を実現するために一時的に保持するデータは異なる。

例えばユーザが登録されているか登録されていないかしかないモデルでは、メール認証中にはユーザが登録されていないけど、メール認証のためのトークンとかはサーバにデータとして持っていないといけない。

もちろん、そういう一時的な状態もモデルに含めるてもあるはず。RDBで実装する場合delete操作が激しくなりそうだけど。セッションキーもそうかな。セッションキーはモデルを表すデータに持つことは少なさそう。モデルの表現には含まれないログイン状態として扱われるイメージがある。揮発性のあるデータストアで保持しそう。

全部モデル化してしまうのが教科書的なんだろうな。汚いとわかるならあえて汚いことをやる必要はないだろう。

モデルではないけど、DBMSの都合について説明する記事があったので貼っとくセッションの保存などにRDBMSよりもRedisやmemcachedのような、NoSQLが向いているのは何故ですか?他にNoSQLの用途として向いている(いない)処理にはどのようなものがありますか? (Quora)

TTLが欲しいよね、という感じか。確かにそもそもセッションキーにはTTLが欲しい気がするし、モデルを考える上でTTLはあまり意識したくない気もする(頭弾けそう)。

反面、TTLもうまく表現したら面白そうな気もするし、割と欠かせないんじゃないかという気もする。そのときに普段のモデルを表現するのに使うDBとTTLを複雑さを吸い取らせるために導入したDBが異なると不必要な複雑さが生じたりするかもなと思った。

今日たくさん寝て軽くランニングしたらなかなか幸せな時間を過ごせた。ただいまはそのクオリティが持続していない。夕食の目処が立っていないこととか部屋がちょっと寒いこと、姿勢が微妙なことが原因だろう。軽く座って作業する空間はやはり欲しい。机にがっつり向かうか後傾でノートパソコンを叩くか、床で作業するかの三択でQOLっぽい作業時間を過ごす空間がない。コメダで作業する姿勢を家でも取れるようにしたいイメージ。やはりベンチソファだと思うんだよな。僕のユースケースだとソファだけでなく机も欲しいことに気がついたのが今週末の成果。

あとは壁が寂しいことにも気がついた。なんか怖くないすっきりとした絵とか飾ればいいんだろうな。めんどいので誰かに決めてほしい。ああいうのってどこで売ってるんでしょうね。

プラットフォーマの良心

プラットフォーマとして、つまり場を提供してその場を幸せな環境として維持するものとしてリーダーシップを発揮することは綺麗なことだと思う。

gmailやyahoo mailがメール送信者のガイドラインを発表して、それを元に受信者・送信者双方にとっての利益を追求したことは記憶に新しい(少なくとも僕にとっては)。風当たりのあることだし、プラットフォーマにとって利益のあるものではない(よね多分)が、それを主導したメールのプラットフォーマたちは綺麗なことをやったと思う。

僕はビジネスとか損得勘定のことはわからないのだけど、あれは間違いなく正しいことだと思う。例えば、あの声明を立案して推進して実行したのが僕だとして(そんなことはまず無理だけど、その責任を僕が負ったとして)、仮にそれが原因で責任を追及され非難を浴びたら、その非難を挙げた人々を憐れむ自信がある。憧れてしまう。ああいうことができる力やセンス・良心をもったプラットフォーマになりたいと思う。自分の良心に従って人の幸せを実現した彼らを尊敬するし、そうなりたいと思う。

ぼくの母校である大和小学校の校歌は「強く、正しく、美しく」を掲げていた。今回掲げた、憧れるプラットフォーマは強さと正しさを持っていた。では美しさはどこにあるだろうか。

RFC8058には美しさを感じた。実際的かつシンプルで、僕の尊敬するエンジニアが美しいと言ってくれそうな哲学を持っているように感じた。ああいう美しさをお前も表現しろよな!というのを校歌は僕に要求しているのだろうか。

あと僕がGAFAに目指すなら絶対Googleに行きます。Googleは美しさと正しさを持っていると思う。ブランディングが大きいのだろうけど。

話が二転三転したけど、正しさや美しさを体現できるだけの強さを手に入れたいと思っています。また、その強さを手に入れる過程で追い求めていた正しさと美しさを忘れずに、むしろよりしっかりしたものにしたいと思う。

推し言語機能 Racket編

この記事はGMOペパボエンジニア Advent Calendar 2023 🎅会場の19日の記事です!

昨日はyagijinさんのReactやってる人向けのSwiftUI入門でした。 Swiftに興味があるReact信者の僕のために書いてくれたのかと錯覚しました。これを期にSwift UI入門しようと思います。 Swift UIは双方向バインディングを採用しているとのことなので、Vueとの類似もありそうですね。

Reactを書いている時間は癒しの時間です。ところでReactは関数型言語からインスパイアされた機能が多いですよね。今日の記事はそんな関数型言語の中でも僕の好きなRacket言語の記事です。僕が一推しするRacketの言語機能を紹介します。

好きなRacket言語の言語機能を紹介します。ざっくりとした紹介なので、ここでの知識を人に話したりプログラミングで活用する前に、節々で参照する公式ドキュメントを参照してもらえると嬉しいです。

  • 契約
  • named let
  • 動的束縛

ここでいう契約とは、関数の入出力の性質を関数定義の際に宣言しておくことで、関数を呼び出しを実行する際に入出力の値を検証し、違反していた場合にエラーを投げる言語機能のことです。余談ですが、契約と型は対応する概念です。契約の検証は実行時に行いますが、型検査はコンパイル時に行います。静的に型をつける言語では関数定義の際にその型を宣言することで、関数呼び出しのあるコードの入出力の方を検証し、違反する呼び出しを特定します。 ContractのRacket Guideを貼っておきます。https://docs.racket-lang.org/guide/contracts.html

ここでは https://docs.racket-lang.org/reference/function-contracts.html の例をお借りして説明します。

> (define/contract (maybe-invert i b)
    (-> integer? boolean? integer?)
    (if b ( -i) i))
> (maybe-invert 1 #t)
-1
> (maybe-invert #f 1)
maybe-invert: contract violation
  expected: integer?
  given: #f
  in: the 1st argument of
      (-> integer? boolean? integer?)
  contract from: (function maybe-invert)
  blaming: top-level
   (assuming the contract is correct)
  at: eval:2:0

冒頭の define/contract で始まるS式では、関数定義をしつつ、その関数の契約を宣言します。二つの引数 i, b をとる関数 maybe-invert を定義していて、bがtruthyなら-iを返しbがfalthyならiを返す関数として実装しています。この関数の契約は(-> integer? boolean? integer?) と宣言されています。これはinteger?を満たす値とboolean?を満たす値を引数に取り、integer?を満たす値を返す関数である、と読みます。

(maybe-invert 1 #t) という関数呼び出し式では第一引数に 1, 第二引数に #t を渡しているので入力に関する契約を満たしていて、返り値は-1になるので出力に関する契約も満たしています。そのためエラーが出ずに何事もなく計算結果の -1が表示されます。

一方で、 (maybe-invert #f 1) という関数呼び出しでは引数の順序を間違えて渡しているようです。第一引数にfalseを表す #f を渡しています。#finteger? を満たさない(そういうふうに integer?が定義されている)のでRacket処理系は契約に違反している旨をエラーとして表示しています。

こういうのが契約です。ちゃんと確認していませんが、PHPで型注釈を書いた際にも実行時の検査が行われるそうなのでPHPは契約を言語機能としてサポートしているといえそうです。他にはD言語も契約をサポートします。

入力値のバリデーションはコードを書くときに当たり前に行う作業ですが、それをシステマチックに行うためのフレームワークを言語が提供してくれるのは魅力的だと思っています。また、契約は型システムや漸進的型つけとも密接に関わりがある楽しい概念です。

次はnamed-letです。これについても公式ドキュメントを貼っておきます。https://docs.racket-lang.org/reference/let.html#%28form._%28%28lib._racket%2Fprivate%2Fletstx-scheme..rkt%29._let%29%29

RacketやSchemeなどのLisp系言語で勉強しているとwhileやforは習いませんが、再帰を習います。例えば整数のリストを受け取って、その和を返す関数sumを定義するにはこんな感じで書きます。

> (define (sum lst)
          (if (nil? lst)
              0
              (+ (car lst) (sum (cdr lst)))))
> (sum '(1 2 3 4 5 6 7 8 9 10))
55

nil?はリストが空を判定し、carはリストの先頭要素をとる関数で、cdrはリストの先頭を除いた部分をとる関数です。先頭の値とそれ以降の和をたすことで、リスト全体の和を得ています。

このように再帰があればループはかけるのですが、関数を定義してその直後にその関数を呼び出す、そしてその後その関数は使わない、みたいなケースがしばしばあります。そういうときに役立つのがnamed-letです。以下のように再帰関数の定義と関数呼び出しを同時に行うことができます。

> (let sum ((lst '(1 2 3 4 5 6 7 8 9 10))
       (if (nil? lst)
           0
           (+ (car lst) (sum (cdr lst))))))
55

再帰関数を使ってループを書くことでループの中での再代入を避けることができます。そのためループ不変条件を把握するのが楽になります。そしてnamed-letを使うことで、不要な関数定義を省くことができます。スコープにある変数は少ないほど嬉しいです。ここだけで使う再帰関数なんだということが一目でわかります。あと書いてみるとわかるのですが、named-letを書くととても気分がいいです。

最後は動的束縛です。emacs lispの変数束縛は動的だということで有名ですし、最近だとReactのContextが動的束縛っぽいかなと思います。やはり公式ドキュメントのリンクを貼っておきます。https://docs.racket-lang.org/guide/parameterize.html

誤解を恐れながらいうと、環境変数みたいなやつをコードの中で設定できる機能です。公式ドキュメントの例をそのまま貼り付けます。

> (parameterize ([error-print-width 5])
    (car (expt 10 1024)))
car: contract violation
  expected: pair?
  given: 10...
> (parameterize ([error-print-width 10])
    (car (expt 10 1024)))
car: contract violation
  expected: pair?
  given: 1000000...

REPLで2回プログラムを実行しています。(expt x y)xy 乗です。それのcarを取ろうとしています(carはリストの先頭要素を返す関数でした)が、(expt x y)の計算結果は数値であってリストでないのでcarの契約に違反します。そのためエラーメッセージが表示されています。今回フォーカスしたいのは動的束縛です。parameterizeerror-print-widthの値をそれぞれの実行で 510に指定しています。その結果表示されるエラーメッセージの幅が5になったり10になったりしています(10...1000000...)。おそらくエラーメッセージを表示する関数の中で error-print-widthが参照されているのでしょう。

このように関数を呼び出すタイミング側でその振る舞いを変えられるのが動的束縛の旨みです。関数の引数で渡す必要がないので、動的変数を参照する関数と設定する関数の間の関数たちが余分な引数を取らなくても良いわけです。

グローバル変数を使ってもこのような引数を介さない設定はできますが、動的束縛を使う方が衛生的です。例えば一つのプログラムの中でグローバル変数の値を変えたい場合、グローバル変数の値を書き換えることになります。これは悪名高い可変なグローバル変数を使うことを意味します。可変なグローバル変数は無関係に見えるプログラムの実行順序がクリティカルにプログラムの振る舞いを左右するのでよくないです。

一方で動的束縛では関数呼び出しごとに値を設定するため実行順序のことは気にしなくて良いです。値を設定した呼び出しの範囲下ではそれが反映されるし、その範囲外ではその設定は無効化されます。このように衛生的に、かつ疲れない形で広い範囲で参照する値を設定できることがグローバル変数と比較した際のメリットだと思います。

動的束縛される変数を参照する場合、呼び出し側の不慮の事故によって変数の定義もれでプログラムが正常に動作しないかもしれません。環境変数を設定し忘れるとアプリケーションが動かないのと同じです。こういう事故は実行する前、例えばコンパイルしたり型検査のタイミングで気がつけると嬉しいですよね。

Racketでこの課題を解決できるかは知らないのですが、エフェクトハンドラとエフェクトシステムを使えば型検査の中で解決できます! その説明をしたい気持ちが溢れているのですが、そろそろ日を跨ぎそうなので興味がある方は僕に声をかけてくれると嬉しいです。

プログラミング言語の言語機能、いいですよね。言語設計者が思う表現のベストプラクティスが詰まっていて触れるたびに嬉しくなります。

明日のアドベントカレンダーは冷静沈着なTepiさんがTextのJetpack Composeで画像表示した話を書く予定とのことです。 Jetpack Composeは名前しか聞いたことがないので、新しい概念を見られそうで楽しみです!

それでは良いクリスマスを!

2023-10-28

ジャンププラスの表示がどなっているか気になって開発者ツールでみたらなんかすごかった。アプリケーションのストレージにページをバラバラにしてパッチワークみたいにしたデータがあって、恐らくそれをいい感じに繋ぎ合わせて表示する感じでcanvas要素を使っているみたい。スクレイピングとかで漫画を引っこ抜かれないための仕組みなんだろうし、パッとわかるものではないだろうけど気になる。はてなのGigaViewrが使われているとのこと。ヒントとか開発話みたいなものが聞けないかなと思ってポッドキャストを聞いている。

2023-10-27

https とかで通信をするときはローカルにインストールされているCA証明書を参照する。 ubuntuの場合 /etc/ssl/certs/ca-certificates.crt がそれで、適当に名前を変えるとhttpsでcurlできなくなる。

🐧 curl https://pepabo.com -vvv
*   Trying 13.225.183.31:443...
* Connected to pepabo.com (13.225.183.31) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* error setting certificate file: /etc/ssl/certs/ca-certificates.crt
* Closing connection 0
curl: (77) error setting certificate file: /etc/ssl/certs/ca-certificates.crt

2023-09振り返り

今月はインカレの運営準備と仕事を頑張った。またカレーとボルダリングを始めた。

インカレでは人に仕事を回す仕事でしっかりキャパオーバーした経験をできた。おかげで価値観を少し変えることができて、瞬殺できるタスクはすぐに瞬殺するのが楽だと思えるようになったし、瞬殺できない仕事もなんとか小さくしようともがけるようになった。この辺りは仕事でも意識しているところで、二つのサンプルがうまいこと僕の中で補い合って学びを得る機械になってくれた形だと思う。どちらもちゃんとした人たちが一緒に仕事をしてくれてフィードバックもくれる環境だから実現しているのだと思う。感謝だし、この環境に身をおけた運と自分を褒めてあげたい。

カレーもオリエンテーリングと職場の人たちが相補的に絡み合って好きになり始めた。ボルダリングもそうか。今の僕は職場とオリエン界隈の二つのコミュニティに支えられて生活を営んでいるみたいだ。充実している。いいこと。

ここまではいわゆるソフトスキルみたいな仕事をする上での能力とか趣味の話だったけど、純粋な技術の話でいうとWebアプリケーション開発のレイヤが低めのところが(どのくらいかわからないけど)強くなった。Rackみたいな構成とかDNSの話(間接参照は偉大だ)、アーキテクチャの成長のさせ方とかを新たに腹落ちさせた。

10月は趣味を深めつつ、ソフトスキルっぽい面ではきっちり仕上げるところを重視する。ガッとやる。技術はネットワークとかを深められると嬉しい。趣味は今のを深めていく。ボルダリングは週2回いけるといいなと思う。

GASでスライド生成

Google Slidesで作成したテンプレートファイルに文字列を置換する形でスライドを生成するスクリプトをChat GPTに書いてもらったのでメモ。

+--------------------------------+
|                                |
|  {{氏名}}                      |
|                                |
|                                |
|     {{住所}}                   |
+--------------------------------+

みたいなスライドを作って、

氏名,住所
佐藤太郎,日本のどこか
田中一郎,東京のどこか

みたいなスプレッドシートでスクリプトを実行すると以下のようなスライドをテンプレのあるスライドに追記する。

+--------------------------------+
|                                |
|  佐藤太郎                      |
|                                |
|                                |
|     日本のどこか               |
+--------------------------------+

+--------------------------------+
|                                |
|  田中一郎                      |
|                                |
|                                |
|     東京のどこか               |
+--------------------------------+

スクリプトは以下。

function createSlidesFromSheet() {
  var slideId = 'ここにスライドのIDを入れる'
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  var data = sheet.getDataRange().getValues();
  
  var slide = SlidesApp.openById(slideId);
  var templateSlide = slide.getSlides()[0]; // テンプレートとして使う最初のスライドを取得
  
  var headers = data[0]; // ヘッダー行を取得

  // データ行をループ
  for (var i = 1; i < data.length; i++) {
    var row = data[i];
    var newSlide = slide.appendSlide(templateSlide); // テンプレートスライドをコピー
    
    var shapes = newSlide.getShapes();
    for (var j = 0; j < shapes.length; j++) {
      var shape = shapes[j];
      var text = shape.getText().asString();
      
      // スプレッドシートのヘッダーを参照して、対応するデータでプレースホルダーを置き換える
      for (var k = 0; k < headers.length; k++) {
        var placeholder = '{{' + headers[k] + '}}';
        text = text.replace(placeholder, row[k]);
      }
      
      shape.getText().setText(text);
    }
  }
}

2023-09-09

tomlもyamlも難しいので、みんなjsonを書けばいいのにと思う。 Goとか静的型付け言語とかが流行って、読みやすさの意義が重要視されている時代なはずなのに、設定ファイルは書きやすさとか、見栄えの良さが重視されていそうなフォーマットが人気なのが解せない。 jsonがナウいんじゃないかと思うし、好みとしてもjsonがいいなと思う。

jsonは誤解することが一番少なそうだし、みんな何が嫌なんだろう。編集がちょっとたいへんとか? そんなに設定ファイルを編集している時点で大変なことになっているのだから、それは妥当な大変さ何じゃないかと思うのだけど。

契約と型検査

プログラミングの型検査・契約・テストについて書きます。お酒を飲みながら書きました。注意は払ったつもりですが、変なところがあるかもしれません。

  • 契約とは何か
    • 例を含める
  • どんな嬉しさがあるか
  • 型検査との兼ね合い

契約 (contract) とはプラグラムの関数の入出力に関する規約のことです。例えば整数の割り算をする div 関数は、二つの整数を受け取って商を返す関数だとしましょう。このとき、入力の二つの値は

  1. どちらも整数
  2. 二つ目の整数は0ではない

ことが求められます。また、整数の割り算を行なっているので、div(a,b) の値は例えば

  1. a の絶対値以下であること

が求められます(もっと細かい要求をしても良いでしょうが)。箇条書きで示したような div 関数について求められる性質のことを契約とよぶことが多いです。

ここまでで例を示しました。例のことは忘れて一旦抽象的な定義を試みましょう。契約は関数を呼び出す側と呼ばれる定義の間の約束事です。関数を正しく呼べば正しい結果を返すことを規定します。どんな呼び出しが正しくて、正しい呼び出しをされたと仮定とした上でどんな結果が正しいかを規定するのが契約です。

先ほどの例を考えると、 div 関数の第二引数に0を渡すのは呼び出し側の契約違反で、div(168,4) の結果が42にならないのは関数定義の契約違反です。契約は、関数呼び出しにおける呼び出し側と定義側との間の規約を表明し、検査します。

多くの言語でコードを書く際は、関数の冒頭で引数のチェックをして、呼び出し側の責任を追及するスタイルでコードを書くことになりがちです。言語によっては組み込みの機能でいい感じに契約を書いて、実行時に検査できます。 D言語とかRacketがいい例です。

例えばRacketだと、モジュールでエクスポートする関数を表明する箇所で、関数の契約を書きます。完全に雰囲気ですが、おそらくこんな感じで書くんじゃないかったかと思います。正確にはRacket GuideかRacket Referenceをご覧ください。

#lang racket

(export
  (div (-> (and int (lambda (x) (< 0 x) )) int  int)))

...

(define (div a b)
  (/ a b))

契約を書いておくと何が嬉しいでしょうか。問題の切り分けが楽になることが嬉しいですね。Blame shiftingができます。みなさん人生で一回は Segmentation fault とか Null pointer exception とか car: cannot apply for nil みたなエラーに遭遇したことがあるかと思います。これらのエラーは契約をちゃんと関数に書いていないから起きるはずで、まともなライブラリを使っていればあまりみないはずです。これらのエラーが出たときには割と深く絶望して、どの関数が悪さをしているか探す旅が始まります。

もし真面目に契約を書いていれば関数が許さないnilを受け取った時点で呼び出し側に責任があることを即座にエラーを起こしたり、変な結果を返しそうになったら返す直前に同様にエラーを起こします。

これが契約の嬉しさです。反対に、関数を動かして契約違反で怒られない限り、その契約を実装が遵守していることが保証されます。これもまた契約の嬉しさの一つです。契約はプロダクション環境で生きているドキュメントとして機能します。

テストとの違いは、契約は実行時に検査をすることが大きいでしょう。テストはテストを走らせるときにしか検証を行いませんが、契約は実行時にも検査を行います。プロダクション環境で関数を呼び出すときにも契約は検査されるのです。

契約はいいものであることがわかったと思います。関数定義の性質を保証して、何かあればすぐに検出し、何もなければ、すべてのそれまでの実行で違反したケースがないことを保証します。

この観点で見たときに、型検査はテストよりも契約に近しい存在だと言えるでしょう。型検査は、コンパイルのたびに型制約が満たされていることを検証します。健全な(まともな)型システムでは、型検査をパスしたプログラムは実行時に型エラーを起こさないことが保証されます (この保証がある型システムのことを健全だというので順番は逆ですが)。型検査では、関数の入力として渡される値が、関数が期待する条件を満たすことを検査しますし、関数が返す値が宣言にあっていることも検査します。契約と対比させると、契約は実行時に検査を行う一方で、型検査はコンパイル時に行うという感じです。

逆にいうと、契約は型検査で静的にやろうとする検査を実行時まで遅延したものです。実行時には任意の計算をできるので表現力は契約の方が高いです。例えば引数の値が10と20の間である、みたいなことを検査するのは型検査では大変ですが、契約ならちょちょいのちょいです。

じゃあ契約だけでいいじゃないか、型検査なんてやめてしまえ!という話になるかというと、そういうわけにもいきません。型検査には契約にないよさがあります。

型検査の良さは静的に検証が済むことにあります。つまり、以下の二つを型検査は満たします

  1. 全ての実行について、検証結果が成立する
  2. プログラムを実行しないでも検証を行える

まず一つ目について。契約やテストでは、実行した場合については動作を検証してくれますが、それとは違う値については特に保証をしてくれません。だから境界テストみたいな、人間が上手に動かす技法が使われるのでしょう。型検査では、ある程度検証内容を抽象的にしたり保守的にすることで、全ての実行に対する性質を保証します。 intが返る関数は決してfloatを返さないことを型検査では保証できます。

抽象化や保守的な検査を行う二つ目の恩恵として、実行しないでも検証できることが挙げられます。本番環境で動かさないとわからなかったり、テスト環境をせっせと用意する必要は、型検査では生じません。

型検査や契約の有用性を主張してきましたが、それでもテストは必要です。実際に色々な具体的なケースで動かすことでわかることは多いでしょう。型検査は動かさないでもわかることを検証して、契約は動かしたらわかることを検証します。テストはプログラムを動かしてみて検証します。型や契約だけではプログラムを動かすことはありません。そこが大きな違いなはずです。

それでも全ての異常の検知をテストでまかなう必要もないはずです。契約や型検査は保証をする仕組みとして優秀です。基本的な保証は契約や型検査で済ませて、本当に際どいところをテストでカバーする、みたいな役割分担をすると幸せになれるんじゃないでしょうか。

dotfilesのセットアップスクリプトを書いた

dotfilesをGitHubで管理しているのだが、今までは設定ファイルの管理だけで、インストールは手動で行なっていた。設定ファイルを使いまわせるだけでだいぶ便利なんだけど、コンテナ環境の中で作業したくなると、手動インストールに耐えられなくなる。そこで重い腰を上げてセットアップを自動化した。

git のインストールと以下の実行でok。 nvimとかfishとかcargoとかが入る。

git clone https://github.com/naoyafurudono/dotfiles.git
bash dotfiles/setup.sh

test

arm環境かつubuntuだけでしか動かしていないが、dockerコンテナでセットアップスクリプトを動かして、正常に終了するかを確認するテストを書いた。

この手のセットアップスクリプトのテストって、世の中ではどのようにテストしているんだろう。以下の難しさがテストを大変にしている気がする。

  • 環境依存な部分をうまく吸収する必要があること
  • インストール失敗の判定が難しいこと

2023-07-29

ARM64でいろんなサイズの整数の足し算をする方法を整理する。サイズごとに演算が用意されているわけではなく、レジスタの指定方法(x,wの使い分け)や、レジスタのコンテンツをいい感じにすることで、 byte, half, word, double wordの足し算を実現する(と思ってよさそう)。

  • レジスタどうしの足し算では、destinationとその他の二つのsourceレジスタのサイズが同じじゃないといけない。結果のサイズがdouble wordならXnを使えばいいし、word以下ならWnを使う。
  • レジスタのコンテンツをいい感じにする方法は二つありそう
    • 適当なマスクとandを取る
    • 専用の命令を使う。二種類観測した。
      • Armv8-A Instruction Set Architectureが優しい。7.4節Extension and saturationに説明がある
      • 一つ目は拡張命令を使う方法。符号{あり,なし}と拡張前のサイズについて、それぞれ定義された拡張命令を使うと、destinationレジスタにsourceレジスタを拡張したビット列がセットされる。
      • 二つ目は足し算で追加の引数として拡張方法を指定する方法。拡張命令と似たような感じのenumが定義されていて、それをadd命令のsourceレジスタの後にしていすると第二sourceレジスタを指定した方法で拡張した上で足し算する。

朝はお茶漬けを久しぶりに食べた。朝にお米を食べようと思うと、やっぱりお茶漬けがいい。子供の頃に抱いた感覚が長持ちしている。一時期パンに手を出したこともあったけど、なかなか難しい。食パンは口の中の水分を持っていくので惣菜とかが一緒にないとちょっと難しい。小倉トーストとかは好きなので、全くダメというわけではないと思うのだけど。

2023-07-22

コンパイラの実装で、次はポインタ算術をやる。演算子がオーバーローディングされているので型検査が必要。今は環境とかのデータ構造を設計する気力がなくて、パソコンを前にふにゃっとしている。お昼ご飯食べたら考える。

興味本位でコンパイルしたプログラムの実行速度を測ってみた。時間計算量が試数時間なfibの実装(あのみんな大好きなナイーブなやつ)で、 fib(40)を計算してみた。自作コンパイラだとuser時間が1.3secくらいなのに対して、 gccのO3でuser時間が0.3secくらいだった。 O3を指定しないと(多分O2)0.5secくらい。 Inliningとかは効かないだろうし、ループ周りでの最適化もできないはず。スタックマシンではなくレジスタマシンとして動かすことで(無駄なpush/popを排除することで) O2くらいの速さになってる感じかな。 O3では何が早くなってるんだろう。気が向いたら調べるか、実装するかしたい。

お昼を食べて買い物に行ったあと、型検査器を実装した。がんばった。 strcmpがboolを返すと思い込むやつをやって時間を溶かした。ランニングをしてオーバーロードに取り組む。今はintもポインタも64bitにしているけど、abiをみたらintは32bitっぽいので合わせる。オーバーロードは楽しそうだけどintを32bitにするのが面倒。 ASTに型を行き渡らせたので難しくはないはず。

買い物ではズボンを買いに行った。涼しい長ズボンが欲しかったので。初めて買う感じのやつを変えて満足している。サンダルも欲しかったけど、僕の期待が矛盾していることに気がついたので断念。来年は期待を変えられることを願って今年はスニーカを履き続ける。

Cとかその辺の関数型言語を使っていると欲しくなる言語機能第1位は動的束縛だという説を提唱したい。代数的エフェクトほどのことを普段使いに人類は求めているとは僕には思えなくて (普段使いと言ったのは、凝った仕組みを作る場合はのぞきたい気持ちの表れ)動的束縛が欲しいんじゃないだろうか。オブジェクト指向でインスタンス変数を使うのもこの用途が多いんじゃないかと勝手に思っているんだけどどうだろう。

とにかく、動的束縛が欲しい。動的束縛はいいぞの会を結成するまである。

Uを叩くとメチって音がする。髪の毛でも入り込んでしまったかもしれない。割とストレス。

2023-07-21

https://github.com/naoyafurudono/comp

早いもので作り始めてから2週間たったみたい。もっとサクサク進むと思っていたのだけど、しばらく楽しめそう。

自作CコンパイラでCのプログラムの一部をコンパイルできるようになった。これまでは変数宣言をできなかったので型宣言のあるmain関数を読めなかったが、 intだけ許容するようになったので、初めてCのプログラムをコンパイラが受け付けたことになる。

こんなコードをコンパイルすると、

int main()
{ 
  int a; int b; int i;
  a=0; b=1; i=0;
  while(i < 10)
  { 
    int t; 
    t=a+b; a=b; b=t; 
    i=i+1; 
  }
  return a;
}

こんなアセンブリを吐く。 SSAみたいな中間表現を挟んでレジスタ割り付けを真面目にやるのはいつがいいんだろうか。

.globl _main
.text
.balign 4
_main:
    stp x29, x30, [SP, #-16]!
    mov x29, SP
    sub SP, SP, #32
    mov x0, #-16
    str x0, [SP, #-16]!
    mov x0, #0
    str x0, [SP, #-16]!
    ldr x0, [SP], #16
    ldr x1, [SP], #16
    str x0, [x29, x1]
    str x0, [SP, #-16]!
    mov x0, #-24
    str x0, [SP, #-16]!
    mov x0, #1
    str x0, [SP, #-16]!
    ldr x0, [SP], #16
    ldr x1, [SP], #16
    str x0, [x29, x1]
    str x0, [SP, #-16]!
    mov x0, #-32
    str x0, [SP, #-16]!
    mov x0, #0
    str x0, [SP, #-16]!
    ldr x0, [SP], #16
    ldr x1, [SP], #16
    str x0, [x29, x1]
    str x0, [SP, #-16]!
.L0:
    mov x1, -32
    ldr x0, [x29, x1]
    str x0, [SP, #-16]!
    mov x0, #10
    str x0, [SP, #-16]!
    ldr x1, [SP], #16
    ldr x0, [SP], #16
    cmp x0, x1
    cset x0, lt
    str x0, [SP, #-16]!
    ldr x0, [SP], #16
    cbz x0, .L1
    mov x0, #-40
    str x0, [SP, #-16]!
    mov x1, -16
    ldr x0, [x29, x1]
    str x0, [SP, #-16]!
    mov x1, -24
    ldr x0, [x29, x1]
    str x0, [SP, #-16]!
    ldr x1, [SP], #16
    ldr x0, [SP], #16
    add x0, x0, x1
    str x0, [SP, #-16]!
    ldr x0, [SP], #16
    ldr x1, [SP], #16
    str x0, [x29, x1]
    str x0, [SP, #-16]!
    mov x0, #-16
    str x0, [SP, #-16]!
    mov x1, -24
    ldr x0, [x29, x1]
    str x0, [SP, #-16]!
    ldr x0, [SP], #16
    ldr x1, [SP], #16
    str x0, [x29, x1]
    str x0, [SP, #-16]!
    mov x0, #-24
    str x0, [SP, #-16]!
    mov x1, -40
    ldr x0, [x29, x1]
    str x0, [SP, #-16]!
    ldr x0, [SP], #16
    ldr x1, [SP], #16
    str x0, [x29, x1]
    str x0, [SP, #-16]!
    mov x0, #-32
    str x0, [SP, #-16]!
    mov x1, -32
    ldr x0, [x29, x1]
    str x0, [SP, #-16]!
    mov x0, #1
    str x0, [SP, #-16]!
    ldr x1, [SP], #16
    ldr x0, [SP], #16
    add x0, x0, x1
    str x0, [SP, #-16]!
    ldr x0, [SP], #16
    ldr x1, [SP], #16
    str x0, [x29, x1]
    str x0, [SP, #-16]!
    b .L0
.L1:
    mov x1, -16
    ldr x0, [x29, x1]
    str x0, [SP, #-16]!
    ldr x0, [SP], #16
    mov SP, x29
    ldp x29, x30, [SP], #16
    ret
    mov SP, x29
    ldp x29, x30, [SP], #16
    ret

2023-07-19

実装しているCコンパイラ で関数定義をできるようになった🎉。今までも既存のコンパイラで作ったオブジェクトファイルとリンクすれば呼び出すことはできていたが、自分で定義した関数がある程度ちゃんと呼べるようになった。

まだ型がlongしかないので道は長い。

https://github.com/atweiden/fzf-extras ここが良さげ。

2023-07-17

Cコンパイラをarm macで実装しているのだけど、a=b=0; return b;"みたいなコードがセグメント違反で落ちる。 lldbで調べてみると、main関数は正しい値をw0にセットしてretできていそうなんだけどその後の動的リンクされたコードでエラーが発生しているみたい。設定する値を変えるとエラーにならずに実行が終了する。謎である。

ABIを守っていないのが悪さをしているかも。

土曜日はパソコンしてた。お昼頃に連絡が来ていたことに気がついて、翌日の約束をした。

勢いで日曜日は丹沢に行くことになって、卒業ぶりに会った友達と2時間くらいの登山をしてきた。コースタイムが4時間だったのでいいペースだった。最近登山をしておらずペースタイム通りの時間でいく想定をしてしまっており、思ったよりもあっさりと終わってしまった。友達の靴が下山した後の道で壊れてしまったのでサンダルを貸して歩くことに。風呂に入ってからはま寿司で3時間くらいお茶を飲んで帰宅した。

日曜日は海の日なので海を目指して部活の後輩と走った。天王洲アイルが海の近くだったのでそこまで行ったのだが、思ったよりも海っぽくなかったのが残念。久しぶりに走ったので走り始めがだいぶ辛かった。

久しぶりの人と会うと時間の流れを感じる。

arm64のメモ

Cコンパイラを実装するためにarm64のことを調べている。この記事はそのメモ。

よくあるソフトウェアのライブラリについているドキュメントとは毛色が違う。

Arm macを使っている人の話です。

  • 既存コンパイラがはくアセンブリを覗く方法
    • アセンブリをはく: gcc -O0 -S
    • ディスアセンブル: otool -vVt
  • デバッガで調査する

アセンブリ命令って割と体系的になってなくてやばいイメージがあったけど、 arm64は秩序がある程度あるように感じている。まだ深淵を覗けていないだけかもしれないが。汎用レジスタの名前が簡単なことが大きいかもしれない。

2023-07-08

椅子に座るほどの元気がなくてもパソコン座れるので楽しい。気軽にコーディングできる。

cコンパイラ実装するやつは、今からローカル変数の定義に入るところ。ここまでで、四則演算と比較をコンパイルできるようになった。 armでやっているのだが今のところそんなにx86と違わない。 push/popでスタックポインタがarmだと16byte境界にしか設定できないとか、割り算がシンプルだとかくらいの違いしか観測していない。

そういえばenumは値だった。変数名みたいにコンパイラがよしなにするやつというイメージが強くて戸惑ってしまった。今回初めてcファイルを頭を使って分割した。定義と宣言の違いを認識して活用する日強がある。

パーサ前はサクッとできて、コード生成も一応形にはしたのだが、生成したアセンブリをアセンブルして実行するとセグフォで落ちる。 x29にSPをmovするだめみたい。x29以外にしたらどうだろうと思い、x9を使ってみたらセグフォのタイミングが変わった。ちゃんと追ってないので明日起きたら追ってみよう。

とりあえず、armのマニュアルを落とした。めちゃ長いけど良さげ。ソフトウェアと違って、ライブラリが無い分こういうふうに一つのでかいドキュメントが提供されるのはなんかそうなんだろうな、という感じがする。Web版よりも検索しやすいのはいいこと。今日はこれくらいにしよう。

ちなみに今はラフロイグ10年を飲んでいる。いいでしょ。

動画を見たり手を動かすことが増えた。あとは仕事でドキュメントを読む時間が増えて、活字が安定供給されているのが影響しているかも。

とはいえ仕事で読むドキュメントは、読み物としてはそんなに面白く無いことが多い。その分手を動かしてものを作るのが楽しいからいいのだけど、小説を読む楽しみとか、心に響く論文を読む感覚が足りない。小説とか論文とかに飽きてきたのはあるのかもしれない。残念ながら深掘りできる人間ではなかったのか。広く学ぶ好奇心とかがあるわけでもないのだけど。

話題になっていたのは当時から認識していたが、ずっとみていなかったユーフォを見た。特に第一シーズンが好きで、上手くなりたい、のあたりが響いている。僕がある程度まじめに考えて方向性を決めるときには、上手くなりたいが奥底に合ったなと再認識させられた。

頑張っているときはわからないけど、少し環境が変わると上手くなっていたことがわかる。加えて、そのときになって周りから、それが上手い人というラベルを貼られることに気がつくし、振り返ると上手くなったなと気がつく。上手くなりたいと憧れた、あの頃の自分からすると今の自分は割といい線行ってるんじゃないかと思う側面がある。全部が全部上手くなってるわけじゃないけど。

この頃は、上手くなった先に何があるのかということをちらほら考える。幸せがあると思っていたのだが、実際のところはどうなんだろうか。今は体力と好奇心と自尊心がボトルネックになって、ボトルネックになってることがそれらを削っていくんじゃないかと思う。また、自分が上手くなるのにかかる時間が実感を通して認識できたことで、自分の限界を認識するようになるのだろう(僕はまだ認識してない。アカデミアのスターにも総理大臣にも、経済界のドンにも縁があればなれると思ってる。巡り合わせに依ると思ってる時点で擦れているのかもしれないけど)。

僕はアニメを見て、アニメの感想ではなく内省をアウトプットしたくなってしまうので自分から進んでアニメの話をしたくならない。聞かせるのは悪いなという気持ちとなんか恥ずかしい気持ちがある。日付が変わってしまいそうなのでこのくらいで。ところでフロムザバレルは甘い。干し芋っぽい風味がする。

明日はランニングしよう。午前中に走ってみる。

2023-07-02

末尾位置での関数呼び出しは、継続渡し形式ではcaleeに渡す継続をcallerが大きくしないで、 callerのcallerから渡されたものをそのまま渡す点で特徴的だ。レジスタマシンではcallerのスタック領域をcalleeが上書きして使うことに対応するのだろう。こういうcall命令はどのくらい実用されているのだろうか。

https://www.sigbus.info/compilerbook これを読んでいる。

高校の化学の授業でナトリウムをどうやって保存するべきかと先生が問いを投げて、追い討ちをかけるようにそのまま先生が水筒ですか、と言ったのをたまに思い出す。確か灯油とかに放り込んでおくのが定石だった気がする。

今日は水筒を買った。会社で水をもっと飲みやすくなる。水筒にはお茶もコーヒーも入れないつもり。レジで「ご自宅用ですか?」と聞かれたのが印象的。プレゼントか否かを暗に問われたのだと思ってそうですと言ったのだが正しく意図を汲み取れていたのだろうか。家で水筒使うことなかなかなさそうなので明には嘘をついてしまった。

意図が自明ではない発言にはその背景を添えて欲しいし、自分も添えるように気をつけよう。

報酬主義を超えてを読み始めた。思ったよりも面白い。ある程度、当たり前の主張をさも常識を疑って得られた結論みたいな書き方をするけど、それでも僕の立脚する価値観を疑うようなことも書いてありそうなので期待している。

2023-07-01

envsubstを使うと標準入力の環境変数の参照っぽいところに環境変数の値を埋め込んだテキストを吐ける。 readmeにコマンドのヘルプメッセージを載せたいときに便利。例: https://github.com/naoyafurudono/tools/tree/main/cl

gitで管理しているファイルのパスが得られる。 git grepみたいに管理対象だけに興味があるときに便利そう。 fzfとの相性が良さげ。

2023-06-30

すでにgit管理されているファイルをgitignoreでマッチするようにしても、管理から外れない。外すためには以下のようにすると良い。

git rm -r --cached .
git add .
git commit -m 'update with .gitignore'

2023-06-29

crate.ioに初めてコードを登録した。cargo install で入るから便利。ちょっとしたCLIツール書く体験がなかなか良い。 copilotが面倒なことやってくれる。

crates.io

Railsとか書いてると深いところに元からあるファイルをコピーしたいことがちょいちょいある。そのときに長いパスを2回打ちたくないので作った。

2023-06-24

macのタイムゾーンの設定が狂っていて、今日の投稿がこれと前回の二つに分かれてしまった。

今日はmacの設定と、以降に伴って壊れたちょっとしたCLIツールの修正した。昔Rustで雑に書いたもので、エラー処理が辛そうだったので少し勉強して改善した。 anyhowを使ってみたい気持ちが湧いたけど、まずは基本的なところからということでトレイトオブジェクトを使うことにした。type Result<T> = std::Result<T, dyn Error>みたいな感じにすることで、いろんなエラーを孕んだresultに?を使うことができて幸せ。

一箇所ムムッとなったのが、クロージャの中で?を使う箇所。dyn Errorの気持ちで書いていたら、推論器はもっと具体的な型を推論していたみたいで、二つ目のエラー型の式に対して?したら型エラーになってしまった。こういうときはアノテーションをつければ良い。 Rustの型推論の割り切り方に慣れていない。

2023-06-23

macを買って環境構築をしているのでメモしていく。

  • capslock -> eisu toggle
    • システム環境設定 > キーボード > テキスト入力 > 入力ソース > Caps LockキーでABC入力モードに切り替える
    • 最近のmacは組み込みの設定で変更できるようになった
  • 1Password
  • CLIツール: 以下の順で入れると良い。気が向いたらインストールスクリプトを書こう
    • brew
    • fish
    • nvim
    • .config
    • その他
  • gitでsshを使うための設定: この投稿のおまけを参考に
    • 鍵を生成
    • githubに公開鍵を登録
    • .ssh/configを書く

個人メモ:dotiflilesに書いてあるのでコピペは不要。

# for fish
function _ssh-keygen
  set name $argv[1]
  mkdir -p "$HOME/.ssh/$name"
  ssh-keygen -t ed25519 -f "$HOME/.ssh/$name/id_ed25519"
  chmod 600 "$HOME/.ssh/$name/id_ed25519"
end
#!/bin/bash

name=$1
mkdir -p "$HOME/.ssh/$name"
ssh-keygen -t ed25519 -f "$HOME/.ssh/$name/id_ed25519"
chmod 600 "$HOME/.ssh/$name/id_ed25519"

Host github.com
  User git
  IdentityFile /Users/naoyafurudono/.ssh/github/id_ed25519

Terraformでローカル環境の管理とかできないだろうか?

2023-06-10

共感できるところが多かったし、なるほどなと思うところもあった。なにより読んでて楽しかったので読んでよかった。

野崎まどの本を読むのは、野崎まど劇場を友達に借りたのが最初だった気がする。かれこれ10年くらい前の話かも知れない。

天気予報を確認したいのだけど、テレビを見たり朝スマホを確認する習慣がないし作る気もないので、なにか方法が必要。ちょうどラズパイが手に入ったので、毎朝どこかから引っ張ってきた天気予報を喋ってもらおうかと考えている。

読み上げは、voicevoxがいろいろいい感じなので試してみるつもり。ドキュメントがあまり充実してなさそうなのがたまにきず。やってみた系のブログ記事が有ったのでメモ https://ponkichi.blog/raspberry-voicevox/

天気予報はどこから取ってくるのがいいんだろう。とりあえず、傘が必要かどうかを知りたい。

CAMPHER-が主催した植山類さんの講演でyoutube配信があったので視聴した (youtube)。リンカの話はよく知らなかったので楽しかった。「『CSの大体の問題は間接参照で解決する』という言葉がある」という発言がなかなか面白かった。使いたくなるときに我慢して使わずに乗り越えられたら幸せになったりするだろうか。

2023-05-13

もともとbashで書いていたスクリプトを拡張したくなって、普段ならPythonで書くところを今日は新しいことをしてみようということでRustをつかってみることにした。

Rustはまったく初めてと言うわけではなくて、ちらちらドキュメントを読んだり、ノリで学校の課題をRustで書いてみたり(痛い目にあった)したことがある。所有権のあたりで苦労はあまりしなかった(というかPythonっぽくヒープを贅沢に使うコードを書いた)のだが、Result / Optionの変換で発狂しかけた(メソッドが定義されていることに思いをはせられずに自作してしまった)。

あまり苦労しなかったと言いつつ、所有権のあたりで困りはしている。参照を受け取るコンストラクタに、その場で作ったオブジェクトを渡したいときに、一旦変数に束縛しないと、渡すオブジェクトが即死してしまっていけない問題が面倒。名前をつけるまでもない、式が体をを表しているような値にまで名前をつかないといけないのはしんどい。コンストラクタが所有権を奪うようにすればよいのだろうか。いらないから参照にしたのだよな…。

今ではそこそこなれてきて、代数的データ型とまともな型検査器がついたPythonくらいの書き方はできるようになった。 Rustのライブラリがイケイケに作られていて(エラー処理周りは辛いと感じるけど)、プログラムを書いていて楽しい。すごく汚く書いてしまった。当面の目標はまともにかけるようになることかな?ちょっとしたCLIでは大差ないのかもしれないけど。

ブログのGitHubのプログラミング言語構成比がカオスなことになってきた。

ここ何日か胃腸炎でつらい。今日はだいぶ回復して、Rustを勉強できるくらいになったけど、まだつらみを感じる。とはいえ三食たべても大丈夫な体に戻りはしたので問題なし。何日か会社に行けなかったのがなかなか悲しい。

今日は以前もらい忘れた診断書を書いていただいた。前回の診療に対して診断書を出してもらうことはなんだか難しそうで、もう一度診察していただくことになってしまった。自分の中では治ったと思っていたけど、見ていただいたらまだ治っていないとのことだったし、今はそう感じる(流されやすい性格なのか?)ので、忠告していただけてよかったと思うことにしている。

病院の帰り道で食器のフリマ的なことを日本料理屋さんがやっていた。普段使っている食器を入れ替えるのかなにかで、安く売り出してくださっていたようだ。胃腸炎になるまえに、会社のランチで「おいしそうな自炊の写真はくろっぽい器が大切」とのアドバイスを頂いていたことを覚えていたので、これは運命だと思い食器を購入した。黒っぽい器はどんぶりしか出会えなかったけど、それがなかなかいい感じだし、白っぽい器もいい感じのにいくつか巡り会えたのでほくほくしている。

あとはおいしそうなご飯をつくればよい。

夕飯につかってみた。いい感じ。味噌汁のお椀(蓋付き)が小さいやつで、フリーズドライの味噌汁一杯分しか入らないやつ(褒めてる)。感動している。

(アマプラ)。グレンラガンの監督?が制作しているらしい。ノリが楽しい。

2023-04-16

午前中はChatGPTとかであそんでいた。ブログを書いていたおかげで、AIに食わせる自分の書いた文書に困らないのが嬉しい。

文書から自分の人柄を表現してもらって、それをもとにSNSで使えるアイコンを生成しようとしたのだけどうまくいかない。人柄の表現はそれっぽいのができるのだけど、表現が抽象的になってしまうので、そのままアイコン画像を生成につかうと小学生のときによんだ漫画にでてきそうな怪しくて怖い宗教っぽい画像がでてきてしまう。

インターネット上でのキャラクタに合わせたアイコンを提案してもらえたら楽しくないだろうか?

ちなみに生成できた画像はこんな感じ。改善のしようはいくらでもありそう。

DALL-Eで生成したもので、権利の問題はなさそう (2023年4月16日閲覧):

Starting today, users get full usage rights to commercialize the images they create with DALL·E, including the right to reprint, sell, and merchandise. This includes images they generated during the research preview.

本腰を入れて文書を読むときは印刷して読みたい。なので長いWebドキュメントを読むときは少し辛いし、論文を読むときは(本腰を入れて読むなら)印刷する。本はたいてい物理の書籍を買っていた。印刷するのが面倒だし、書き込みを残しやすいので。

ただ就職して出社するようになって、移動中に文書を読みたい機会が増えた。そんななかで本を持ち運ぶのは大変で、その日に読みうる範囲だけを持ち運びたくなった。そういう経緯でPDFみたいな印刷しやすい形式で購入できる場合は積極的に電子書籍を買うようになってきた。本のサイズが小さければこれまでと変わらず物理で買ってしまうのだが、面積が大きかったり鈍器の形をしているものは電子書籍を買う。

書き込みが残らなくなる問題は解決できていないが、書き込みたくなるほどまじめの読むことは少ないし、そこまで腰を吸えられるのは結局家の中のはずだ。今の生活ではそんなに困らないだろう。余談だが、EoPLを物理でもっていないのは数少ない書き込みが大切な機会を逸しているように思える。

SNSで情報発信するのがあまり得意ではない。もともと会話があまり得意ではなくて、インスタントに情報を発するのが苦手なのだと思う。なにか考えてから言葉にするのにある程度時間がかかるし、言葉にしてから吟味したくなってしまいもする。

お酒が入ると吟味したい気持ちがどこかにいってしまうからしゃべる量が増えるのだろう。

話を戻そう。SNSは思ったことをパッと書いてそのまま発信することを重視したようなUIをしているように思う。たぶんそういうところで苦手意識を持っている。とはいえ情報発信の場としてSNSがメジャーなのは間違いないだろうし、ここみたいなブログはほとんどの人にみられないだろう。ブログを更新したときにSNSにリンクを投稿すると良い気もするが、それはそれでSNSの苦手な部分がブログ投稿に侵食してきそうで嫌な感じもする。悩ましい。

2023-04-10

この頃「詳解システム・パフォーマンス」を読んでいる。チューニングをする機会はないのでツールの説明は読み飛ばしているが、それに入る前の基礎的な概念を勉強している。学部の授業でやった理論的な基礎から復習して、もう少し具体的な実装とか最近のアーキテクチャのこととかまで勉強できている気がする。

今からファイルシステムの章を読み始める。

2023-04-06

今まではレイテンシを減らすために改札をくぐった際の処理をローカルで行い、その後まったり同期する、みたいな方式をとっているという記事をみた記憶がある。

これからそのように凝ったことはしないで、改札機はクライアント、処理は中央のサーバで行うそうだ。時代が変わったのでそれでもいけるとか。なかなか驚きだ。どんなパフォーマンスチューニングやUXまわりの工夫がされているのだろうか。 Suicaの話は何回聞いてもロマンがあると感じる。運用開始が楽しみだ。

昔Fitbitを使っていたのだけど、日々の記録が安定していておもしろくなかったから一年ほどでやめてしまった。最近通知を腕で受け取りたいとか、ランニングのときにつける時計を変えたいみたいな欲求がでてきて探してみると、 Fitbitが良さげだったので再開することにした。Charge5を使っている。必要十分プラスアルファくらいの機能でいい感じ。ただSlack返信機能を誤作動させてしまったので対策したい。ぱっといじった感じでは無効化する設定を見つけられなかった。あとは腕時計をつけなれてなくてうっとうしく感じるのが欠点。

それ以外はばっちり。ランニングの記録もとれるし、通知もしっかり気がつける。ディスプレイの常時点灯を時間をしていして有効にできるので時計としても完璧につかえる。

2023-04-02

CPythonの開発者向けドキュメントがとてもよい。今はコンパイラの構成に関する部分を読んでいる。抽象構文木の扱いやメモリ管理の方針など、コンパイラ開発の方針を説明している。ドラゴンブックとかからは得られない、開発手法の知識を得られて幸せ。

好きな言語にドキュメントがたくさんあることは本当に嬉しい。

2023-03-31

東大の田浦先生が公開されている大規模ソフトウェアを探るがとてもよかった。 GDBを使って大きなソフトウェアの振る舞いを理解する方法を学べる。 2年ほど前に、こういう資料が喉から手が出るほどほしいと感じていた記憶がある。

今日はこのあと研究のことを少し考え、後輩とお酒を飲む。どちらも楽しみだ。

午前中には入社や書類を仕事をした。 Macのターミナルが重い。今まで使っていた研究室のでも重かったし、新しく使い始めたものでも重い。原因を調査中。アプリを起動するのも重いし、コマンド実行が終了してプロンプトが返るまでのレイテンシもある。

2023-03-19

最近AIが流行っていて、精度がすごいと話題で、生活が多かれ少なかれ変わっていくのだろうなという感じがする。ああいう機械学習ベースのAIは学習で直感を鍛えて、それに基づく出力をするものだと僕は解釈している。人間が頭を使うときには直感を論理とか議論で検証して、主張の穴を見つけて改善するサイクルを回すはずだ。今の機械学習っぽいAIは直感で得た主張を論理で解釈しないだろう(NECがそういうことを考えていそう。それができればAIはもっとつよくなるはずだし、そういうAIを見てみたい。

実現するためにはAIの入出力に使う「言語」に解釈を入れることと、それをもとにして論証を行うことが必要だろう。今のAIは抽象構文木を操作の対象にしていて、それを意味を解釈するようにしたらいいんじゃないかという想像だ。

今ある論理が世の中の事象を扱うのに十分かはわからないし、多分結構不足しているはずだ。機械学習AIのための論理体系の研究とかあったら楽しいだろう。NIIとかでやってないだろうか?

おととい届いたBig Peatがとてもおいしい。明日の研究室飲み会にもっていこう。ちょうど二年くらい前に部活の先輩に勧めていただいたのだが、懐具合の問題で飲めずにいた。少し無理してでも飲んでおいたほうが良かったかと思うくらいには好き。ストレートで飲んでもおいしいし、ハイボールにしてもおいしい。天才か? ぼくはスコッチウイスキー?が好きなのかもしれない。

学部2年のころ、確率論基礎の試験の前日にウイスキーを飲む会に誘っていただいたとき、ラフロイグ・ロアを味見させていただいて半分感動したのを覚えている。あのころは二十歳になりたてでお酒のおいしさは今よりも分かっていなかったのだが、それでもいいかんじなことは分かった。それからラフロイグ・ロアには縁がなかったのだが今気になっている。数量限定なようで、毎年11月ころに発売されそうな雰囲気がある。今もアマゾンで売ってるが、転売価格に見えるので時期がくるまで我慢しよう。

ちなみにBig Peatと一緒に勧めていただいたジョニーウォーカーのグリーンラベルはすでに飲んでいて、 やはり好きな感じだった。

使い勝手の良いデスクトップ向けウィンドウマネージャが欲しい

使い勝手のよいウィンドウマネージャがWindowsとかMacに搭載されることはないだろう。使うアプリケーションやブラウザ、入力デバイスやその使い方によって使い勝手が大きく変わるだろうから。 OSが決め打ちで提供できるものでは無いんじゃないかと思う。なので自分でまじめに使い勝手の良いものを考える必要がある。

先日オリエンテーリングのインカレの配信のお手伝いをしたのだが、そこで使っていたスイッチャがなかなかデスクトップでのウィンドウマネージャの機能として魅力的に感じた。

スイッチャにはいろんなウィンドウ(カメラからの入力や、図、合成用のテロップなど)が接続されていて、すべてが画面の下部に控えめに表示される。それらを見ながらスイッチャのオペレータが放送するためのウィンドウを選択、合成する。放送されるウィンドウは画面上部に大きく表示される。放送されるウィンドウの右に同じサイズでプレビューウィンドウも表示される。これらの違いは放送されるか否かだけで、合成のテストとかに使える。

これを実現するためには操作用のデバイス(このデバイスをスイッチャというようだ)と、大きなモニタが必要だ。

デスクトップのウィンドウマネージャでもスイッチャのように

  • すべてのウィンドウを表示しておいて
  • 本番+alphaくらいのウィンドウをメインエリアに表示する

と便利な気がする。単純にはいかないだろうけど、いい線行きそうだ。

懸念事項は以下の通り:

  • ウィンドウの個数が多くなりそう
  • ウィンドウサイズが固定ではない(アスペクト比)
  • ウィンドウの動的な生成とその配置方法が非自明

エフェクトハンドラの良さと実用性について

エフェクトハンドラで継続や代数的エフェクトを扱う必要性は一ミリもなくて、実用的にそれらが欲しくなることはないか、あるいは限られていてそこまで一般的な機能を提供する必要はないんじゃないかと感じている。

このあたりを議論するために

  1. エフェクトハンドラの嬉しさ
  2. 意味論の歴史的経緯
  3. 改善ポイント

を考える。

なお、この記事はとくに裏付けもなく書いている。気が向いたら裏付けをしようと思っているが、この記事の目的は僕の考えの整理であって、世に主張をしたいわけではない。

記事の内容は不正確なことを留意されたい。

エフェクトハンドラが実際的 (practical) なプログラミング言語でエンドユーザに使わせたくなるのは

  • エフェクトシステムと相性のよい意味論
  • 動的束縛

を提供したいからではないだろうか。エフェクトハンドラを言語に入れれば、それで表現できる操作は自動的にエフェクトシステムで追跡できるし、ハンドラを用いることでエフェクトをローカルに使えるのは特筆するべきだろう。汎用性とlocal reasoningのしやすさはエフェクトハンドラのもつ良い性質だと思う。

エフェクトハンドラで実現できる動的束縛はとても使い勝手が良い上に、エフェクトシステムで追跡することで使い勝手が上がりそうだ。動的束縛のためだけのエフェクトシステムではなく、もう少し凝ったことができるエフェクトシステムがつくとなお幸せだろうから、エフェクトハンドラみたいな抽象度の比較的高いフレームワークで実現するのは幸せなんじゃないかと感じる。

エフェクトハンドラと呼ばずに “algebraic effects” とか “algebraic effects and handlers” とか呼ぶ流派、時代がある。歴史的には

  • algebraic effects
  • algebraic effects and handlers
  • effect handlers

みたいな流れで登場したはずだ。最初はハンドラはなくて、モナドとかの話をするような人たちが副作用にモナドではない別の表現を与えようとしたんだったか。ここでいうモナドはモナド則とかを真面目に考えるような数学のモナド。代数的エフェクトもその流れの中に(このころは)あったはず。そもそも代数的エフェクトの代数とは、操作が(0だか1こ以上)あって、それらに等式制約を課す。それを満たすようなモデルを持つのが代数 (algebra) である、みたいな世界だっと思う。群とか環は代数だけど、体は代数じゃないみたいな話を聞いたことがある。そういうのりの代数として、エフェクトを表現したらモナドの合成みたいなことを考えるときに幸せだ、という主張がことの発端だった気がする。

ここまでは数学とかモデル理論?とかの話によっていて、あまりプログラミング言語っぽい雰囲気がしない。ハンドラとか継続が入ってきた経緯はしらないが、多分、プログラミング言語に代数的エフェクトを入れるにあたって、モナドのbindやreturnみたいなものを定義するように、エフェクトに意味を与える仕組みとしてハンドラが考えられたんじゃないかと思う。このあたりは論文をまじめに読めば分かるはず。これが確か2014年くらいのこと。

2000年くらいだったかから考えられていたエフェクトシステムとの相性に目をつけたからか知らないが、「代数的エフェクトとハンドラ」を取り入れた言語が2014年ころに登場し始める。2017年くらいにでてくる印象がある。 EffやKokaはこのへんな気がする。このあたりで、エフェクトが代数的であることはとくに気にされなくなっていき、エフェクトシステムと例外ハンドラがうまいこと組み合わさる限定継続演算子くらいの気持ちで代数的エフェクトとそのハンドラが捉えられて、やがて代数的ではないことが気になる人々がエフェクトハンドラと呼ぶようになったのではないかと思っている。

限定継続は本当に必要だろうか。もっとやさしい概念を提供するのにとどめるのはいかがだろうか。ワンショット継続とかに限定する言語もあるが、それは正しい方向性だろうか。

僕たちがほしかったものは、local reasoningしやすいエフェクトシステムとそれで健全に管理できる意味論なんじゃないかと思う。エフェクトハンドラはその条件を満たすけど、もっと使い心地のよい意味論があるはずだと思う。

最後の文をメモしたくてこの記事を書いた。それ以外は文脈である。

Google Cloudの認証を必要とするアプリケーション開発について

Google Cloudの認証・認可はきめ細かくちゃんとしている感じがして、扱うのが難しいと感じていた。少し調べたらApplication Default Credentials with client librariesの説明を見つけて腹に落ちた。これを抑えた上で、それぞれの実行環境でどのようにcredentialをセットアップするかを見ると、プロセスの権限が半分くらいわかる。ここまでで、サービスアカウントがどのようにプロセスに付与されるかを理解できるはずだ。

次に、それぞれのサービスアカウントがどのようなリソースへのアクセスをもつか、それをどうやって設定するかを確認すれば認証・認可を自由に管理できるんじゃないかと思う。How Application Default Credentials worksが良い水先案内に見える。

このあたりは知識がないと本当に挙動がわけわからないので分かりやすいところにドキュメントを置いといたり、積極的にエラーメッセージで教えてほしい。 Google Cloudを使う上での義務教育だと感じた。

Linux (gnome) でよくやる設定

GNOMEというかLinuxというかでよくやる設定を列挙する。キーボード系が多いと思う。

以下を実行

gsettings set org.gnome.Terminal.Legacy.Keybindings:/org/gnome/terminal/legacy/keybindings/ next-tab '<Primary>Tab'
gsettings set org.gnome.Terminal.Legacy.Keybindings:/org/gnome/terminal/legacy/keybindings/ prev-tab '<Primary><Shift>Tab'

参考: https://askubuntu.com/questions/133384/keyboard-shortcut-gnome-terminal-ctrl-tab-and-ctrl-shift-tab-in-12-04

xremapxkeysnailを使うどちらもそんなに使い心地は変わらないと思う。今はxkeysnailを使っている。

課題が2つある:

  • xkeysnailuinputを必要とすること
    • sudoが必要とreadmeに書かれているのはこれが理由
  • xkeysnailをsystemdに登録すること
    • sudoつけられない/等価なことはできない?

以下のように解決する

  1. 必要な権限を自分に与える
    1. sudoなしでxkesynailを実行できるようになる
  2. systemdに登録して、ログインくらいのタイミングで有効にする

これの通りにやればよい: https://github.com/mooz/xkeysnail/issues/64#issuecomment-600380800

  1. 設定ファイルを書く https://github.com/naoyafurudono/configs/blob/main/systemd/user/xkeysnail.service
  2. ~/.config/systemd/user/におく
    1. バイナリをおく: 上の例では~/.local/binにおいてあることを想定している
  3. systemdに登録する: systemctl --user enable --now xkeynail
    1. enableで登録、--nowで今実行

もしうごかなかったらjounalctl -rでsystemdのログをみる。

https://github.com/naoyafurudono/configs/blob/main/mozc/ibus_config.textproto~/.config/mozc/におく。

参考: https://blog.nfurudono.com/posts/mozc-default-engine/

2023-02-27

Gentooが入った。基本的に待っているだけではあるのだけど、それがなかなか大変。パッケージを一瞬でインストールできる幸せに気がついた。割とすぐにUbuntuに戻るかもしれない。今はnodejsとtexliveをコンパイルしている。未だかつてなくCPUが仕事をしている。かわいそうに。とはいえportageに触れるのはなかなか楽しい。

mozcの設定はこのブログのメモに助けられた。過去の自分に感謝。

(追伸) Gentooを入れるためにssdを付け替えたのだけど、そのときにじゃまで外したCPUクーラーがうまくはまっていなかった。このPCはまともな冷却なしでもろもろをビルドしていたのだ。本当にかわいそうなことをしてしまった。ずっとうるさかったのでさっさと気がつくべきだった。今はこれまでがうそのように静か。

2023-02-26

Golangをすごく久しぶりに書いた結果、構造体の要素がコピーされることを忘れておりデバッグに時間を溶かした(コピーした構造体のフィールドを書き換えて、コピー元に変化が起きると思い込んでいた)。最近はPythonやTSか、関数型言語ばかり書いていて、Cっぽい構造体の扱いをしていなかったので忘れてしまっていたのだろう。忘れていたけど、CやGoのように構造体の要素をコピーする意味論は好き。直感的というか、明示的にポインタを表現することが好きなのだろうか。

PCの構成メモ

PCを自作して使っているのだけど、どんなパーツを使ったか忘れて後でなにか買い足すときに互換性があるかわからなくてこまる。今回調査してメモしておく。

Ubuntuを入れて使っているけど特に不満はない。不満はないのだが、この間Gentooのことを教えてもらって面白そうなので使ってみようと思っている。

余談だが、このPCは親に就活で必要だろうからといって渡してもらったお金で組んだのだった。自由に使えと言ってもらったが、きっとスーツとかを想定していたのだろう。幸いなことにスーツは買わずに済んでいるので(兄のお下がりがまだ着れる)、ずっと気になっていた自作PCに手を出すのに使ったのだった。少し後ろめたい気持ちがないでもなかったが、Linuxとか触るの楽しいことが分かって仕事でもこの手のものを触りたいと思えたし、面接の話のネタにもなったので結果オーライだろう。学校とか本で学ぶOS周りの技術をそのまま試せるのが僕には嬉しかったのだろう。Windowsでは厳しいし、Macもどこか違っているので。