Lensとは

## Lensとは、初級者Haskellerの苦い思い出

　さあさあ、やって参りました。

　Haskell何個目かの鬼門にして、素晴らしく便利なアイツ、Lensの時間です。

　初級者HaskellerにとってのLensといえば、「これを知らなきゃ初級者Haskellerにもなれない」と突然突きつけられて、何かと思って蓋を開ければ地獄のような型が覗く、恐怖と畏怖の対象でしょう。

　調べてみても、様々な言葉で説明されるLensは、いかにもつかみどころのないものに思えます。

- Lensはgetterとsetterのペア
    - 参考: [Lensの仕組みがわかった#lensを自作してみる](https://qiita.com/sgmryk/items/c467af40c6c9df0f95a1#lens%E3%82%92%E8%87%AA%E4%BD%9C%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B)
- [レンズは余状態余モナドの余代数だった](https://gist.github.com/lotz84/7fd7e279bd7196c6baab)
- `type Lens s t a b = forall f. Functor f => (a -> f b) -> s -> f t`
    - [Control.Lens.Combinators#t:Lens] (https://hackage.haskell.org/package/lens-5.0.1/docs/Control-Lens-Combinators.html#t:Lens) より

　一方で、Lensは使うだけなら簡単です。
　「よく分からないが、このようにすれば動く」というもやもやを胸に秘め、初級者HaskellerはLensを知ってひとつ大人になるのです。

　それぞれの説明を確かめながら、Lensについての理解を深めていきましょう。

## Lensとは、getterとsetterのペアである

　一番平易な説明から見ていきましょう。
　getterやsetterという単語は、オブジェクト指向言語を学んだことのある人には馴染みがあります。

```Java
class S {
    private A a;

    public A getA() {
        return this.a;
    }

    public void setA(A a) {
        this.a = a;
    }
}
```

　このような`getX`や`setX`を、getterやsetterと呼ぶのでした。

　Haskellでは下のような関数で表しますね。

```Haskell
data S = S A

getA :: S -> A
getA (S a) = a

setA :: S -> A -> S
setA (S _) a = S a
```

　型に注目すると、getAの型は`S -> A`, setAの型は`S -> A -> S`となっています。
　`S`がオブジェクトの型で`A`がフィールドの型ですね。

> Lensとは、getterとsetterのペアである

　ということなので、getterとsetterのペアにLensと名付けてみます。

```Haskell
type Lens s a = (s -> a, s -> a -> s)
```

　こんな単純なものが果たして本当にあの複雑怪奇なLensなのでしょうか。疑わしいので、実際に確かめてみましょう。

　まずはお馴染の演算子`(^.)`, `(.~)`を定義します。
　この演算子は引数の順番を入れ替えただけの単純なgetterとsetterです。

　先ほど実装したLensは単純なgetterとsetterのペアですから、`fst`と`snd`を使ってgetterとsetterを取り出すことができます。
　取り出したgetterとsetterを使って`(^.)`, `(.~)`を定義してみます。

```Haskell
get :: Lens s a -> (s -> a)
get = fst

set :: Lens s a -> (s -> a -> s)
set = snd

(^.) :: s -> Lens s a -> a
(^.) = flip get
infixl 8 ^.

(.~) :: Lens s a -> a -> s -> s
(l .~ a) s = set l s a
infixr 4 .~
```

　それと、Lensを合成する演算子と、getterとsetterからLensを作るコンストラクタを定義します。

```Haskell
compose :: Lens a b -> Lens b c -> Lens a c
compose (ab, aba) (bc, bcb) = (ac, aca)
  where
  ac = bc . ab
  aca a = aba a . bcb (ab a)
infixr 9 `compose`

lens :: (s -> a) -> (s -> a -> s) -> Lens s a
lens = (,)
```

　これだけあれば、Lensとして最低限の仕事ができるようになります。試してみましょう。
　先ほど出した`S`と`A`の例を使いましょう。

　まずはgetterとsetterの組でLensを作成します。

```Haskell
data S = S A deriving (Show)

getA :: S -> A
getA (S a) = a

setA :: S -> A -> S
setA (S _) a = S a

a :: Lens S A
a = lens getA setA

data A = A Int deriving (Show)

getX :: A -> Int
getX (A x) = x

setX :: A -> Int -> A
setX (A _) x = A x

x :: Lens A Int
x = lens getX setX
```

　作ったLensを使ってみます。

```Haskell
>>> :{
    let s = S (A 100)
    print $ s ^. a `compose` x
    print $ s & a `compose` x .~ 200
:}
100
S (A 200)
```

　この使用感は間違いなくLensと言っていいでしょう。
　唯一の文句といえば、合成を`.`ではなく`compose`と書かなければならない点でしょうか。

　本当にgetterとsetterのペアからLensを構成することができるとは、驚きですね。

　ところで、lensパッケージのLensに比べると型引数が少ないのが気になった人がいるかもしれません。
　getterとsetterとで別の型引数を使うように変えてみると、私たちの知るLensの型になります。

```Haskell
type Lens s t a b = (s -> a, s -> b -> t)
```

　この章のコードはこちらに載せてあります。

https://ideone.com/EfhR9V

## Lensとは、余状態余モナドの余代数である

　何を言ってるのか分からないかもしれませんが、そういうことらしいです。

　とりあえず、今までのように字面を追ってみましょう。
　余状態余モナドとは、Storeコモナドとも呼ばれているもので、次のようなものです。

```Haskell
type Store s a = (s -> a, s)
```

　型だけ見ると、getterとオブジェクトのペアのように見えますね。

　余代数というのは[F余代数](https://ja.wikipedia.org/wiki/F%E4%BD%99%E4%BB%A3%E6%95%B0)のことです。
　ある自己関手$F : C → C$があった時に、次のようなある対象と射の組$(A, α : A → F A)$をF余代数と呼びます。

　Haskellで表すなら次のような感じでしょうか。

```Haskell
type FCoalgebra a = forall f. Functor f => a -> f a
```

　モナドが関手でもあるように、コモナドも関手ですので、この`f`にはStoreコモナドを入れることができます。

```Haskell
type Lens s a = s -> Store a s
```

　できました。これが余状態余モナドの余代数です。

　エイリアスを展開すると、getterとsetterのペアの同型であることが分かります。

```Haskell
type Lens s a = s -> (a -> s, a)
```

　これはgetterとsetterのペアと同じ計算能力を持つということですから、同じようにしてLensにできそうですね。

<details><summary>GetterとSetterの組とStoreコモナドの余代数の同型射の例</summary><div>

```Haskell
type GetterSetter s a = (s -> a, s -> a -> s)
type StoreCoalgebra s a = s -> (a -> s, a)

fromStoreCoalgebra :: StoreCoalgebra s a -> GetterSetter s a
fromStoreCoalgebra f = (snd . f, fst . f)

toStoreCoalgebra :: GetterSetter s a -> StoreCoalgebra s a
toStoreCoalgebra (getter, setter) s = (setter s, getter s)
```

</div></details>

　改めて、まずはお馴染の演算子`(^.)`, `(.~)`を定義してみましょう。

```Haskell
get :: Lens s a -> s -> a
get l s = let (_, a) = l s
           in a

set :: Lens s a -> s -> a -> s
set l s = let (a, _) = l s
           in a
 
(^.) :: s -> Lens s a -> a
s ^. l = get l s
infixl 8 ^.
 
(.~) :: Lens s a -> a -> s -> s
(l .~ a) s = set l s a
infixr 4 .~
```

　簡単ですね。

　次に、Lensを合成する演算子と、getterとsetterからLensを作るコンストラクタを定義します。
　ここまでできてしまえば、もうLensと言っても差し支えないのでした。

```Haskell
compose :: Lens a b -> Lens b c -> Lens a c
compose f g a = (ba . cb, c)
    where
    (ba, b) = f a
    (cb, c) = g b

lens :: (s -> a) -> (s -> a -> s) -> Lens s a
lens get set s = (set s, get s)
```

　できましたね。
　後はgetterとsetterでの実装と同じように利用することができます。

https://ideone.com/D8VThV

## Lensとは、forall f. Functor f => (a -> f b) -> s -> f t

　何が何やら。しかしこれが本命です。

　[lens](https://hackage.haskell.org/package/lens-5.0.1/docs/Control-Lens-Combinators.html#t:Lens)パッケージの`Lens`の定義を読むと、次のように書いてあります。

```Haskell
type Lens s t a b = forall f. Functor f => (a -> f b) -> s -> f t
type Lens' s a = Lens s s a a
```

　型引数の数が少ない、`Lens'`の方で読み替えてみましょう。

```Haskell
type Lens' s a = forall f. Functor f => (a -> f a) -> s -> f s
```

　Storeコモナドの実装に似ている気がします。`a -> f a`はF余代数でしたね。
　このことから、あるF余代数の射を別のF余代数の射に移すような関数であることが分かります。

　これまで通り`get`と`set`を定義して、お馴染みの演算子`(^.)`, `(.~)`を定義してみましょう。
　これまでとは違い、かなり複雑です。

```haskell
get :: Lens s a -> s -> a
get l s = getConst $ l Const s

set :: Lens s a -> s -> a -> s
set l s a = runIdentity $ l (const $ Identity a) s

(^.) :: s -> Lens s a -> a
s ^. l = get l s
infixl 8 ^.

(.~) :: Lens s a -> a -> s -> s
(l .~ a) s = set l s a
infixr 4 .~
```

　`get`のときと`set`のときとで関手`f`の解釈が変わっています。

　`get`のときは`f`が`Const a`ですから、Lensは下のような型に特殊化されます。

```Haskell
type Getting s a = (a -> Const a a) -> s -> Const a s
```

　`set`のときは`f`が`Identity`ですから、Lensは下のような型に特殊化されます。

```Haskell
type Setter s a = (a -> Identity a) -> s -> Identity s
```

　「渡される関手によってgetterやsetterになる関数」がLensの正体ということだったわけですね。

　Lensの合成とLensのコンストラクタも作ります。
　ここで、このLensの実装では`compose`が関数合成と同じになることに気が付きます。つまり、今まで`compose`と書いていた部分を`.`で繋げられるようになるということです。さすが本命バージョンです。

```Haskell
compose :: Lens a b -> Lens b c -> Lens a c
compose = (.)

lens :: (s -> a) -> (s -> a -> s) -> Lens s a
lens get set f s = set s <$> f (get s)
```

https://ideone.com/sviwER

## おまけ: Lens圏

　これまで実装してきたLensたちは、どれも`compose :: Lens a b -> Lens b c -> Lens a c`を備えていました。
　この型、よく見ると関数合成にそっくりです。（事実、最後のLensは関数合成そのままで実装しましたね）

　実は、この合成を使って`Category`を実装することができます。
　これをLens圏と呼びます。

```Haskell
instance Category Lens where
  id = lens id (const id)
  (.) = flip compose
```

## おわり

1. Lensをgetterとsetterのペアから構成できることを確認しました。
2. Lensを余状態余モナドの余代数から構成できることを確認しました。また、これがgetterとsetterのペアと同型であることを確認しました。
3. [lens](https://hackage.haskell.org/package/lens-5.0.1/docs/Control-Lens-Combinators.html#t:Lens)パッケージの`Lens`はgetterにもsetterにもなるふしぎ関数であることを確認しました。

　今回実装したLensは型引数を2つしか取りませんが、これをもう少し一般化して型引数を4つ取るようにすると普段使っているLensになります。（getterとsetterの例でやりましたね）
　また、さらに一般化していくとopticsと呼ばれる様々なLensの亜種を得ることができ、逆にLensはopticに制限を書けたものだという理解もできるようになります。

　opticについては、こちらのスライドが分かりやすいので、ぜひ読んでみてください: [Opticから見たLens/Prism](http://tokiwoousaka.github.io/takahashi/contents/20150530LensPrism.html)

参考:

- [Lensの仕組みがわかった#lensを自作してみる](https://qiita.com/sgmryk/items/c467af40c6c9df0f95a1#lens%E3%82%92%E8%87%AA%E4%BD%9C%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B)
- [レンズは余状態余モナドの余代数だった](https://gist.github.com/lotz84/7fd7e279bd7196c6baab)
- [Control.Lens.Combinators#t:Lens](https://hackage.haskell.org/package/lens-5.0.1/docs/Control-Lens-Combinators.html#t:Lens)