Lens
ややこいので以下のように呼び分けよう
Lens
そもそもある概念
具体的な型
この辺が良いらしい
自分で定義した型に対してsetterやgetterなどの便利関数を自動生成する
TSではclassを作って、そのインスタンスに対して、データを更新したりgetしたりするが、それと同じようなことを関数型の世界でも行う
関数合成などのデザインもきれい
ネストがあるタプルやレコードの操作時にありがたくなる
逆にネストがなければそんなにありがたくない
tutorial
Lensを使って生成したgetterやsetterのことを「
lenses」と呼ぶっぽい

まあ単数形でもいいけど、わかり易さのために複数形にしてる

「Lens」と呼んで指す対象が多すぎる

package名
生成されたgetter/setter
特定の1つの関数
基本的にはこれさえ抑えておけばできる
makeLens
or makeFields
fmap
多くの場合
makeFields
を使えばいい?

普通に .
アクセスする
view
over
set
over :: ASetter s t a b -> (a -> b) -> s -> t
これはsetter
view :: MonadReader s m => Getting a s a -> m a
これはgetter
^.
というエイリアスがある
例
hsdata Atom = Atom { _element :: String, _point :: Point } deriving (Show)
data Point = Point { _x :: Double, _y :: Double } deriving (Show)
$(makeLenses ''Atom)
$(makeLenses ''Point)
-- use
> let atom = Atom { _element = "C", _point = Point { _x = 1.0, _y = 2.0 } }
> view (point . x) atom
1.0
ghci> atom^.point.x
1.0
ghci> atom^.point^.x
1.0
> over (point . x) (+1) atom
Atom {_element = "C", _point = Point {_x = 2.0, _y = 2.0}}
以下は全て同じ意味
hsview (point . x) atom
atom^.point.x
atom^.point^.x
.^
は view
のエイリアスなので、1行目と2行目がおなじになるのはわかる
3行目は、統一感のためにあるのだろうか
普通はどれを使うんだろう

2行目かな
関数合成
Lens'
型で単純化して見るとわかりやすい

型の前後は、普通の関数合成
.
と同じ感じになっっている

hspoint :: Lens' Atom Point
x :: Lens' Point Double
point . x :: Lens' Atom Double
Lens Laws
getterとsetterが以下の3つを満たす
set s (get s) == s
get (set s v) == v
get (set (set s v1) v2) == v2
フィールド系
makeLenses '' Hoge
setter
+~
, -~
, *~
フィールドが数値の場合に使える
+~10
なら元の値に10を加算する
例.hs{-# LANGUAGE TemplateHaskell #-}
data Par = Par {
_foo :: Int,
_chi :: Chi
} deriving (Show, Eq)
data Chi = Chi {
_piyo :: String
} deriving (Show, Eq)
makeLenses ''Par
let par = (Par 1 (Chi "child"))
-- getter
_foo par -- 普通のアクセス
par^.foo -- Lensでのアクセス
par^.chi^.piyo -- チェーンもできる
("Piyo", par)^._2.foo -- タプル系の関数と組み合わせる
-- setter
par&foo.~3 -- 3に変更
par&foo+~10 -- 10加算する
makeFieldsを使う
mkLabelというのもあるらしい
タプル系
(^.) :: s -> Getting a s a -> a
演算子
view
関数のエイリアス
_1
: 1番目を取得
hs(1, ('a', 'b', ("Hoge", "Piyo")), 2)^. _2 . _3 . _1
関数合成
(.)
をOOPのmethodに見立てているの面白い

(.~) :: ASetter s t a b -> b -> s -> t
値の変更
set
関数のエイリアス
hs _1._2.~True $ ((1,2),3) -- ((1,True),3)
(&) :: a -> (a -> b) -> b
hs((1,2),3)&_1._2 .~ True -- ((1,True),3)
値の変更
to
ネストの深い部分に関数を適用した結果を得る
hs("hoge", ("a", "nya"))^._2._2.to length -- 3
以下の違いってなに
hs$(makeLenses ''Atom)
makeLenses ''Atom
$(..)
って何の意味がある?順序とか?
Lensが型
実装が複数ある
何でもできるが、読み解くのが難しい
コンパクト
data-lensというパッケージもあるが、それは古いやつ
Lens内の型
Equality
Iso
Getter
Setter
Review
圏論
Lensの実装が気になる
実装読んでないけどけっこう難解?らしい

後半
参考
概要がわかりやすい
Lensに関する大量の資料集
template haskellを使ってるので若干嫌われてる?