Lens
#WIP
ややこいので以下のように呼び分けよう
Lens
そもそもある概念
Haskellのlens
HaskellでLensを実装したpackage
Lens型
具体的な型
この辺が良いらしい
https://www.schoolofhaskell.com/school/to-infinity-and-beyond/pick-of-the-week/a-little-lens-starter-tutorial
https://hackage.haskell.org/package/lens-tutorial-1.0.4/docs/Control-Lens-Tutorial.html
https://medium.com/@russmatney/haskell-lens-operator-onboarding-a235481e8fac
自分で定義した型に対してsetterやgetterなどの便利関数を自動生成する
TSではclassを作って、そのインスタンスに対して、データを更新したりgetしたりするが、それと同じようなことを関数型の世界でも行う
関数合成などのデザインもきれい
ネストがあるタプルやレコードの操作時にありがたくなる
逆にネストがなければそんなにありがたくない
Template Haskellを使う
tutorial
Control.Lens.Tutorial
https://www.schoolofhaskell.com/school/to-infinity-and-beyond/pick-of-the-week/a-little-lens-starter-tutorial
https://gyazo.com/884987b5a329720c502a8a9b1097f648
Lensを使って生成したgetterやsetterのことを「lenses」と呼ぶっぽいmrsekut.icon
まあ単数形でもいいけど、わかり易さのために複数形にしてるmrsekut.icon
lensesを作る「lens関数」もある
「Lens」と呼んで指す対象が多すぎるmrsekut.icon
package名
生成されたgetter/setter
特定の1つの関数
基本的にはこれさえ抑えておけばできる
lensesを作る
makeLens or makeFields
lens関数
fmap
多くの場合makeFieldsを使えばいい?mrsekut.icon
lensesの合成
普通に.
アクセスする
view
over
set
Control.Lens.Setter
https://hackage.haskell.org/package/lens-4.17.1/docs/Control-Lens-Setter.html
Control.Lens.Getter
https://hackage.haskell.org/package/lens-4.17.1/docs/Control-Lens-Getter.html
over :: ASetter s t a b -> (a -> b) -> s -> t
https://hackage.haskell.org/package/lens-4.17.1/docs/Control-Lens-Setter.html#v:over
これはsetter
view :: MonadReader s m => Getting a s a -> m a
https://hackage.haskell.org/package/lens-4.17.1/docs/Control-Lens-Getter.html#v:view
これはgetter
^.というエイリアスがある
例
code:hs
data 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}}
以下は全て同じ意味
code:hs
view (point . x) atom
atom^.point.x
atom^.point^.x
.^はviewのエイリアスなので、1行目と2行目がおなじになるのはわかる
3行目は、統一感のためにあるのだろうか
普通はどれを使うんだろうmrsekut.icon
2行目かな
関数合成
Lens'型で単純化して見るとわかりやすいmrsekut.icon
型の前後は、普通の関数合成.と同じ感じになっっているmrsekut.icon
code:hs
point :: 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
https://www.schoolofhaskell.com/user/tel/lenses-from-scratch#laws
フィールド系
makeLenses '' Hoge
setter
+~,-~,*~
フィールドが数値の場合に使える
+~10なら元の値に10を加算する
code:例.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を使う
https://syocy.hatenablog.com/entry/2017/08/14/235830
https://stackoverflow.com/a/47854987
https://hackage.haskell.org/package/lens-4.15.4/docs/Control-Lens-TH.html#v:makeFields
https://stackoverflow.com/questions/25585650/whats-the-difference-between-makelenses-and-makefields
mkLabelというのもあるらしい
タプル系
(^.) :: s -> Getting a s a -> a
演算子
view関数のエイリアス
_1: 1番目を取得
code:hs
(1, ('a', 'b', ("Hoge", "Piyo")), 2)^. _2 . _3 . _1
関数合成(.)をOOPのmethodに見立てているの面白いmrsekut.icon
(.~) :: ASetter s t a b -> b -> s -> t
値の変更
set関数のエイリアス
code:hs
_1._2.~True $ ((1,2),3) -- ((1,True),3)
(&) :: a -> (a -> b) -> b
code:hs
((1,2),3)&_1._2 .~ True -- ((1,True),3)
値の変更
to
ネストの深い部分に関数を適用した結果を得る
code:hs
("hoge", ("a", "nya"))^._2._2.to length -- 3
#??
以下の違いってなに
code:hs
$(makeLenses ''Atom)
makeLenses ''Atom
$(..)って何の意味がある?順序とか?
Lensが型
合成可能なfunctional reference
実装が複数ある
lens
何でもできるが、読み解くのが難しい
lens-family-core
https://hackage.haskell.org/package/lens-family-core
コンパクト
data-lensというパッケージもあるが、それは古いやつ
Lens内の型
Equality
Iso
Lens型
Traversal型
Getter
Setter
Review
Iso型
Prism型
圏論
http://ziphil.com/diary/application/27.html
圏同型
https://kseo.github.io/posts/2016-12-10-encodings-of-lense.html
https://m-hiyama.hatenablog.com/entry/2021/11/12/112110
https://m-hiyama.hatenablog.com/entry/2021/11/18/115103
テレオロジー圏
加群圏
Lensの実装が気になる
実装読んでないけどけっこう難解?らしいmrsekut.icon
https://qiita.com/sgmryk/items/c467af40c6c9df0f95a1
https://debug-ito.hatenablog.com/entry/20150102/1420177718
http://www.scs.stanford.edu/14sp-cs240h/slides/lenses-slides.html#(1)
https://www.schoolofhaskell.com/school/to-infinity-and-beyond/pick-of-the-week/a-little-lens-starter-tutorial
https://www.slideshare.net/itsoutoftunethismymusic/ekmett-17955009
後半
/LugendrePublic/【WIP】ゼロから作るLens(和訳)
https://github.com/ekmett/lens/wiki/Overview
https://github.com/shiatsumat/wiwinwlh-jp/blob/master/mds/レンズ.md
https://qiita.com/sparklingbaby/items/e66f48224067647d8e67
参考
https://en.wikibooks.org/wiki/Haskell/Lenses_and_functional_references
http://www.scs.stanford.edu/14sp-cs240h/slides/lenses-slides.html
Ekmett勉強会発表資料
概要がわかりやすい
haskell | Haskell 俯瞰まとめ
Lensに関する大量の資料集
圏論に関するものもある
https://its-out-of-tune.hatenadiary.org/entry/20130320/1363757820
http://ziphil.com/diary/application/20.html
http://ziphil.com/diary/application/21.html
https://the.igreque.info/posts/2015-06-09-lens-prism.html
https://www.reddit.com/r/haskell/comments/23uzpg/lens_is_unidiomatic_haskell/
template haskellを使ってるので若干嫌われてる?
https://dev.to/piq9117/haskell-generating-lenses-for-third-party-libraries-1oik
https://m-hiyama.hatenablog.com/entry/2021/11/12/112110
https://twitter.com/inamiy/status/1507352844399046659
https://blog.jle.im/entry/lenses-products-prisms-sums.html
https://www.tweag.io/blog/2021-04-15-arrows-through-a-different-lens/