最近lensの各型を調べていて、その理解のうちの1つの関門となったのが、
Lens
型のうちGetting
とGetter
、Setting
とSetter
の関係だった。
定義を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
Getting
がGetter
のf
を(r
を外に逃して)Const r
に固定した型になっている。
(簡略) Getting :: (a -> Const r a) -> s -> Const r s
(簡略) Getter :: (a -> f a) -> s -> f s
Const r
はContravariant
Functor Functor
なので、f
に当てはまる。
instance Contravariant (Const a)
instance Functor (Const a)
ということはGetter
はGetting
の一般化である。
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
Setting
はGetting
と1つだけ違って、(->)
がp
に一般化されている。
p
を(->)
に特殊化すると、Getting
のConst r
をIdentity
に置き換えた型になる。
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)
Settable
はApplicative
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 (->) :: * -> * -> *
Identity
はApplicative
Distributive
Traversable
なので
instance Applicative Identity
instance Distributive Identity
instance Traversable Identity
- Control.Applicative (Applicative)
- Data.Distributive (Distributive)
- Control.Lens.Traversal (Traversable)
Setter
はSetting
の一般化である。
追伸
ここのドキュメントコメントが、なぜ-ingを-erに一般化するのかのヒントになるかもしれない。
Anything Settable must be isomorphic to the Identity Functor.
訳) あらゆるSettable
はIdentity
Functorと同型でなければいけない。
この「同型」は圏論的意味だと思う。