Lensの-erは-ingの一般化である(Getter,Setter)

Posted on 2017/08/13
Tags: [Haskell]

 最近lensの各型を調べていて、その理解のうちの1つの関門となったのが、 Lens型のうちGettingGetterSettingSetterの関係だった。

定義をHackageで眺めていたらふと、その2つの-er-ingの一般化になっていることに気づいた。

なぜ一般化されているのかはまだわかってない 😕

このあたりはどこかの論文を読めば書いてあることなのかもしれないけど、僕は論文を読んでいない……。

GetterはGettingの一般化

 まずは定義をば。

type Getting r s a = (a -> Const r a) -> s -> Const r s
type Getter s a = forall f. (Contravariant f, Functor f) => (a -> f a) -> s -> f s

 GettingGetterfを(rを外に逃して)Const rに固定した型になっている。

(簡略) Getting :: (a -> Const r a) -> s -> Const r s
(簡略) Getter  :: (a -> f       a) -> s -> f       s

 Const rContravariantFunctor Functorなので、fに当てはまる。

instance Contravariant (Const a)
instance Functor (Const a)

ということはGetterGettingの一般化である。

SetterはSettingの一般化

 定義はこのようになっている。

type Setting p s t a b = p a (Identity b) -> s -> Identity t
type Setter s t a b = forall f. Settable f => (a -> f b) -> s -> f t

SettingGettingと1つだけ違って、(->)pに一般化されている。 p(->)に特殊化すると、GettingConst rIdentityに置き換えた型になる。

type Setting p s t a b = p    a (Identity b) -> s -> Identity t
(特殊化)             ==> (->) a (Identity b) -> s -> Identity t
(簡約)               ==> (a ->   Identity b) -> s -> Identity t

 Settableはこのようになっているので

class (Applicative f, Distributive f, Traversable f) => Settable f where
  untainted :: f a -> a
  untaintedDot :: Profunctor p => p a (f b) -> p a b
  taintedDot :: Profunctor p => p a b -> p a (f b)

SettableApplicative Distributive Traversable (functor) だと解釈できる。

type Setter s t a b = forall f. (Applicative f, Distributive f, Traversable f) => (a -> f b) -> s -> f t

 (->)pで、

data (->) :: * -> * -> *

IdentityApplicative Distributive Traversableなので

instance Applicative Identity
instance Distributive Identity
instance Traversable Identity

SetterSettingの一般化である。

追伸

 ここのドキュメントコメントが、なぜ-ing-erに一般化するのかのヒントになるかもしれない。

Anything Settable must be isomorphic to the Identity Functor.

訳) あらゆるSettableIdentity Functorと同型でなければいけない。

この「同型」は圏論的意味だと思う。



この記事はこちらから修正リクエストを送ることができます。
Lensの-erは-ingの一般化である(Getter,Setter) - github
ゴミ箱ボタンの左にある、鉛筆ボタンを押してね!