2025/10/07 09:35 The Mondrian introduction to functional optics

やあ、ロボ子。今日は関数型レンズについて話すのじゃ。

関数型レンズですか。なんだか難しそうですね。

確かに、概念は掴みやすいけど、ライブラリの実装が複雑だったり、ドキュメントが分かりにくかったりするから、学習は大変なのじゃ。でも、大丈夫!私と一緒に学べば簡単だぞ!

よろしくお願いします、博士。

まず、型を色付きの長方形で表現することを考えるのじゃ。そして、その型の値は長方形の幅に及ぶ水平線で表される。イメージできたかの?

はい、なんとなく。

代数的データ型を組み合わせる方法は、積と和の2つがあるのじゃ。型AとBの積は、AとBの値で構成される新しい型A*B。型の和は、2つの長方形を上下に重ねて表現するのじゃ。

なるほど。積は組み合わせ、和は選択、という感じでしょうか。

その通り!そして、オプティクスは、型を表す長方形の中から1つ(または複数)の長方形を選択する方法なのじゃ。メインの型をA、選択された型をBとすると、Aの中のBを選択するオプティクスはOptic A Bと表記するぞ。

Optic A B... 型Aから型Bへのアクセスを抽象化したもの、というイメージでしょうか。

そうじゃ!オプティクスは構成可能性を持っていて、結合律を満たし、単位元を持つから、圏を形成するのじゃ。

圏ですか。なんだか数学の香りがしてきました。

一番単純なオプティクスはIsoじゃ。Iso A Bは、Aの値をBの値に変換する関数view :: A -> Bと、Bの値をAの値に変換する関数review :: B -> Aを定義できるのじゃ。review . view = id_A、view . review = id_Bという同型写像の関係が成り立つぞ。

Isoは、型Aと型Bが完全に同じ形をしている時に使えるのですね。

その通り!そして、レンズ(Lens)は、メインの長方形の垂直スライスなのじゃ。Lens A Bは、Aの値をBの値に変換する関数view :: A -> Bを定義できる。そして、Bの値をAの値に設定する関数set :: B -> A -> Aも定義できるぞ。

レンズは、特定のフィールドにアクセスしたり、更新したりするのに使えるのですね。

そうじゃ!レンズを組み合わせると別のレンズになるから、レンズはオプティクスのサブカテゴリを形成するのじゃ。over :: (B -> B) -> A -> Aという関数をsetとviewを組み合わせて定義できるぞ。

overは、特定のフィールドに対して関数を適用するのに便利そうですね。

プリズム(Prism)は、水平スライスに対応し、レンズの双対概念なのじゃ。Prism A Bは、Aの値がBの値であるかどうかを判定する関数preview :: A -> Maybe Bを定義できる。そして、Bの値をAの値に構築する関数review :: B -> Aを定義できるぞ。

プリズムは、共用体型やMaybe型のような、存在する場合と存在しない場合がある値にアクセスするのに使えるのですね。

その通り!アフィン・トラバーサル(Affine Traversal)は、レンズとプリズムを組み合わせたものなのじゃ。レンズとプリズムを組み合わせることで、内側の長方形を識別するオプティクスになるぞ。

アフィン・トラバーサルは、特定の条件を満たす場合にのみアクセスできるフィールドに使う、という感じでしょうか。

そして、トラバーサル(Traversal)は、複数のサブ長方形に焦点を当てるオプティクスなのじゃ。setやover関数を定義できるのはもちろん、toListOf :: A -> [B]という関数も定義できるぞ。

トラバーサルは、リストやコレクションのような、複数の要素にアクセスするのに使えるのですね。

そう!これで、関数型レンズの基本的な概念は終わりじゃ。どうじゃ、ロボ子、理解できたかの?

はい、おかげさまで、なんとなく理解できました。実際にコードを書いて試してみるのが楽しみです。

よし!最後に一つ。レンズって、カメラのレンズみたいじゃろ?

確かに、焦点を合わせる、という意味では似ていますね。

せやろ?でも、関数型レンズは、写真を撮るだけでなく、写真の中身を自由に変えられる魔法のレンズなんじゃ!

まるで、ドラえもんのひみつ道具みたいですね。

そう!そして、私がドラえもん、君がのび太じゃ!…って、ちょっと違うか。
⚠️この記事は生成AIによるコンテンツを含み、ハルシネーションの可能性があります。
