{-# LANGUAGE TemplateHaskell #-}import Control.Lens
data Car = Car {_maker :: String , _spec :: Spec} deriving Show
data Spec = Spec {_name :: String, _year :: Int} deriving Show
makeLenses ''Car
makeLenses ''Spec
\(getter\)の\( ( \verb|^|.) \)では、\(s\)はレコードで、最初の\(a\)はデータを取り出すフィールドで、最後の\(a\)は取り出したデータだ。\(Getting \ a \ s \ a\)は指定されたフィールドからデータを取り出すための関手(あるいは関数)だ。
\(setter\)の\( (. \verb|~|) \)では、\(s\)は入力のレコード、\(t\)は出力のレコード、\(a\)はフィールドで、\(b\)はそのフィールドに書き込む入力値だ。\(ASetter \ s \ t \ a \ b \)は指定されたフィールドを修正した新たなレコードを得るための関手(あるいは関数)だ。
Haskellの関数を簡略化し、ここではアクセスするフィールドの場所が関数の名前の中に含まれる\(getter\)と\(setter\)を、用意することにしよう。そうすると、先ほどの型シグネチャの中の\(Getting \ a \ s \ a\)と\(ASetter \ s \ t \ a \ b \)とが省かれることになるので、次のようになる。
データベースでのこのような操作(図の左側)を、関手(ここではファンクタ\(Store\ a\))で写したのが図の右側である。\(Store \ a \ ( λx \rightarrow (x,b))\)のうち\(a\)は\(get \_1\)の操作を\( ( λx \rightarrow (x,b))\)では\(set \_1\)の操作を表している。これを青色の小文字\( get \_1,set \_1 \)を明示した。カリー化を利用して、\(get \_1 : S \rightarrow A, get \_1 : S \rightarrow A \rightarrow S \)であることに注意して欲しい。
今までの説明は、\(set \_1\)を一回だけ施したものであったが、何回も繰り返した場合はどうなるだろうか。図で示すように\( (x,b)\)を\(Store \ x ( λy \rightarrow (y,b)) \)で置き換えればよい。同じように\( (y,b) \)を置き換えれば、\(set \_1\)を繰り返したときにファンクタ\(Store \ a\)に写された側を得ることができる。ここでもまた青色の小文字\( get \_1,set \_1 \)で明示し、写像された空間での操作が実際どのように表現されるかを明らかにした。
それでは\(Store \ a\)を\(Comonad\)のインスタンスにしてみよう。コモナドは\(extract: W (A) \rightarrow A\)と\(duplicate:W (A) \rightarrow W (W (A)) \)を用意しなければならない。そこで、次のようにしよう。
class (Functor w) => Comonad w where
extract :: w s -> s
duplicate :: w s -> w (w s)
instance Comonad (Store a) where
extract (Store a f) = f a
duplicate (Store a f) = Store a ( \q -> Store q f)
少し使ってみよう。
上図では次のことを行っている。現在のレコードの内容を\( (a,b)\)とする。このレコードへのアクセス( \(setter, getter\)による )を、ファンクタ\(Store \ a \)で写した空間で\(Store \ a \ ( λx \rightarrow (x,b))\)と表すことができる。これに\(extract\)を施すと、元の状態の\( (a,b)\)を得る。
\( (a,b)\)に対する2度の繰り返しのアクセスを、\(Store \ a \)に写像した空間では、\(duplicate \ Store \ a \ ( λx \rightarrow (x,b))\)となる。もちろんこれに\(extract\)を2回施すと、元の状態の\( (a,b)\)を得る。
((\s' -> Store (get_1 s’) (set_1 s’)) . (set_1 s)) a1
= (\s' -> Store (get_1 s’) (set_1 s’)) (set_1 s a)
= Store (get_1 (set_1 s a1)) (set_1 (set_1 s a1))
となり、左辺は
(\y -> Store y (set_1 s)) a1
= Store a1 (set_1 s)
となる。これより、それぞれの\(Store\)の項目同士が等しいことから
get_1 (set_1 s a1) = a1
set_1 (set_1 s a1) = set_1 s