Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
今から始める
Lens/Prism
2016/10/08 Scala関西Summit 2016
お前誰だよ?
Naoki Aoyama
アドテク系Scala エンジニア
コミッター
Twitter: , GitHub:
Monocle
@AoiroAoino @aoiroaoino
Lens/Prism ってご存知ですか?
Scala でLens/Prism を使うモチベーション
ネストした構造に対するcopy メソッドのネスト地獄
様々なデータを共通のインターフェースで操作できる
非侵入的に外側から追加できる
特定のアーキテクチャに依存しない概念
汎用的に使える...
Lens って何?
getter/setter を抽象的にしたもの
purely functional reference
実は
余状態コモナド余代数
(Costate Comonad Coalgebra)
getter/setter ってなんだっけ?
(広く一般的な意味で)オブジェクト指向言語におい
て、あるfield の値を取得するメソッドがgetter で、 field
に値をセットするのがsetter。(広く一般的な意味で)
クラスのメソッ...
getter/setter 再考
特定のclass に依存しない、汎用的な関数と捉えてみる
getter の仕事とは
オブジェクトからある値を取り出す
素直にシグネチャとして表してみると…
オブジェクトS からある値A を取り出す
S => A
// getter
def get[S, A]: S => A
setter の仕事とは
オブジェクトの一部をある値に変更する
素直にシグネチャとして表してみると…
オブジェクトS の一部をある値A に変更する
S => A => S
// setter
def set[S, A]: S => A => S
あるオブジェクトS の各field に対して前述のような
getter/setter が存在した時、 それらを使って汎用的な
get/set メソッドの提供を考える。
↓↓↓
その仕組みを実現するものをLens と呼ぶ。
get/set Lens
class Lens[S, A](
getter: S => A,
setter: S => A => S
) {
def get(s: S): A = getter(s)
def set(s: S, a: A): S...
get/set Lens
getter/setter をコンストラクタの引数として与える。
class Lens[S, A](
getter: S => A,
setter: S => A => S
) {
Lens の値を定義する
case class User(id: Int, name: String)
// User#id 対 Lens
val _id = new Lens[User, Int](
_.id, // getter
user ...
使い方
val user1 = User(100, "John Doe")
_id.get(user1)
// res: Int = 100
_name.get(user1)
// res: String = John Doe
_name.se...
Lens Laws
Lens には満たすべき法則がある。
get/set
set(s, get(s)) == s
set/get
get(set(s, a)) == a
set/set
set(set(s, a1), a2) == set(s,...
ネストしたデータが対象の時は?
ネストした構造に対するcopy メソッドのネスト地獄を
どう解決するか。
Lens の合成を考える
class Lens[S, A](getter: S => A, setter: S => A => S) {
def get(s: S): A = getter(s)
def set(s: S, a: A): S =...
Lens の合成を考える
def ^|->[B](other: Lens[A, B]): Lens[S, B] = new Lens(
s => other.get(this.get(s)), // getter
s => b => this....
試してみよう
case class Message(user: User, body: String)
// Message#id 対 Lens
val _body = ...
// Message#user 対 Lens
val _user:...
Before
val message = Message(User(100, "John Doe"), "Hello")
message.user // res: User = User(100,John Doe)
message.user.n...
A er
val message = Message(User(100, "John Doe"), "Hello")
_user.get(message)
// res: User = User(100,John Doe)
(_user ^|-...
ところで
オブジェクトS にOption 型のfield が存在する場合に
get メソッドが適切に定義できるだろうか?
A == Option[B] となるようなLens を考えてみる。
class Lens[S, A](
getter: S => A,
setter: S => A => S
) {
// ...
}
すると、A がOption[B] となるような場合に
get メソッドが実装出来ない。
class BadLens[S, B](
getter: S => B,
setter: S => B => S
) {
def get(s: S): B ...
ここで、Prism を導入する。
getter の取りうる引数に対して
setter が返すことが可能な値が足りない場合に
Lens だけではカバーしきれない。
↓↓↓
その仕組みを実現するものをPrism と呼ぶ。
Prism
class Prism[S, A](
_getOption: S => Option[A],
_reverseGet: A => S
) {
def getOption(s: S): Option[A] = _getOption(s...
まずは、Some, None に対するPrism を定義する。
// Some 対 Prism
def _some[A] = new Prism[Option[A], A](
{ case Some(a) => Some(a); case No...
一部のユーザーにEmail アドレスの情報を
持たせたくなった場合を想定する。
case class User(id: Int, name: String, email: Option[String])
// User#email 対 Pris...
_some.getOption(_email.get(User(1, "aaa", Option("email"))))
// res: Option[String] = Some(email)
_some.getOption(_email.g...
とてもダサい!!
_email.get, _some.getOption を直接呼び出している
コードの見通しが悪い
getOption の内部がより複雑だった場合
Lens の時と同じように合成を考えれば良い。
Q: Lens とPrism を合成すると何になる?
Lens
Prism
その他
A: Optional
Optics Hierarchie (Monocle)
ref. Monocle の よりREADME.md
Optics Hierarchie (lens)
ref. lens の よりREADME.md
Optional はLens とPrism の両方の性質を持つOptics
※ 下記コードはMonocle の よりOptional.scala
object Optional {
def apply[S, A](_getOption: S =...
Monocle を使って書くと以下の通り。
val user = User(1, "aaa", Some("email"))
(_email composePrism _some).getOption(user)
// res: String ...
\( 'ω')/ウオオオオオアアアーーーッ!
^|->>
^|-?
^<-?
^|->
^<->
\(՞‫)◔ةڼ‬/ウオオオオオアアアーーーッ!?!?!?
ここまでのまとめ
Lens/Prism の概念と使い方を理解した
Optics Hierarchie を知った
Lens の種類
Lens にはコンセプトや実装に応じていくつか種類がある
get/set lens
get/modify lens
Iso lens
Store Comonad Lens
van Laarhoven lens
and so on ...
van Laarhoven Lens
van Laarhoven Lens とは?
2009 年7 月にTwan van Laarhoven さんが書いた の
アイディアが元になったLens で、Haskell の やScala
の のコンセプトの基礎になってる。
blog
len...
def Lens[S, A, F[_]: Functor] = S => (A => F[A]) => F[S]
type Lens s a = forall f. Functor f => (a -> f a) -> s -> f s
閑話休題
traverse 関数はご存知ですか?
def traverse[G[_]: Applicative, A, B](fa: F[A])(f: A => G[B]): G[F[B]]
例えば、F をList、G をOption とすると、traverse 関数は
リスト内の値にf を適用し、全てSome だった場合には
f の適用結果をSome に包んで返し
一つでもNone の場合はNone を返します。
def isEv...
閑話休題おわり
理解する為にgetter/setter を再考してみよう。
setter の再考
setter の再考
冒頭に出てきたsetter の型は以下の通り。
def setter: S => A => S
これはmodify メソッドの特殊形と考えられる。
なので、modify のsignature を取り入れて
def sett...
この型に見覚えない?
trait Functor[F[_]] {
// F[A] => (A => B) => F[B]
def map[A, B](fa: F[A])(f: A => B): F[B]
}
つまり、我々はset/modify をするのに各field に対する
Functor#map が欲しいのだ。
しかし、Functor のinstance をclass のfield 毎にそれぞれ
定義することは現実的ではない...
Functor#map はTraverse#traverse で定義できる
trait Traverse[F[_]] extends Functor[F] {
// F[A] => (A => G[B]) => G[F[B]]
def trav...
つまり、このtraverse の部分を同等な関数に置き換える
ことで、Functor#map のような関数を得られる。この
F[A], F[B] をS と置いてSetter という名前をつけよう。
type Setter[S, A] = S =...
動作確認
val _id: Setter[User, Int] =
(user: User) => (f: Int => Id[Int]) => user.copy(id = f(u.id))
scala> modify(_name)(User...
getter の再考
getter の再考
冒頭に出てきたgetter の型は以下の通り。
def getter: S => A
取得するだけでなく、関数を適用した結果を返すように
def getter: S => (A => A) => A
と、改めて定義する。
この型に見覚えない?
trait Foldable[F[_]] {
// F[A] => (A => B) => B
def foldMap[A, B](fa: F[A])(f: A => B)(implicit mb: Monoid[B]): B
}
つまり、我々はget をするのに各field に対する
Foldable#foldMap が欲しいのだ。
しかし、Foldable のinstance をclass のfield 毎にそれぞ
れ定義することは現実的ではない...
Foldable#foldMap はTraverse#traverse で定義できる
trait Traverse[F[_]] extends Functor[F] {
// F[A] => (A => G[B]) => G[F[B]]
def...
Setter と同様にtraverse の部分を同等な関数に置き換え
ることで、Foldable#foldMap のような関数を得られる。
このF[A] をS と置いてGetter という名前をつけよう。
type Getting[R, S, ...
さて、我々は似たようなsignature を持つGetter/Setter を
手に入れた。これらを並べて見てみよう。
type Setter[S, A] = S => (A => Id[A]) => Id[S]
type Getter[S, ...
これでvan Laarhoven lens の定義を理解できましたね?
def Lens[S, A, F[_]: Functor] = S => (A => F[A]) => F[S]
type Lens s a = forall f. Functor f => (a -> f a) -> s -> f s
しかし、ここで一つ疑問が湧きませんか?
Q: van Laarhoven lens はうまく合成できるのだろうか?
Getter もSetter も中身はtraverse と同等の関数ですね。
なので、代表してtraverse の合成を見てみましょう。
f にId/Const が入ります。 構造のネストする順番と合成
の順序が一致し、左から右へと辿れますね。
traverse
:: (Applicative f, Traversable t) =>
(a -> f b) -> t a -> f...
Haskell でvan Laarhoven Lens の合成はこう書ける。
ghci> set (_2 . _1) 42 ("hello",("world","!!!"))
("hello",(42,"!!!"))
A: Haskell だと超美しく合成できる...
まとめ
Lens/Prism の概念と使い方を完全マスターした
Optics Hierarchie と呼ばれる階層が存在する
Lens には種類がある
van Laarhoven lens はやばい
今から始める Lens/Prism
今から始める Lens/Prism
Upcoming SlideShare
Loading in …5
×

今から始める Lens/Prism

4,982 views

Published on

2016 年の http://summit.scala-kansai.org/ で発表した資料です。

Published in: Engineering
  • Be the first to comment

今から始める Lens/Prism

  1. 1. 今から始める Lens/Prism 2016/10/08 Scala関西Summit 2016
  2. 2. お前誰だよ? Naoki Aoyama アドテク系Scala エンジニア コミッター Twitter: , GitHub: Monocle @AoiroAoino @aoiroaoino
  3. 3. Lens/Prism ってご存知ですか?
  4. 4. Scala でLens/Prism を使うモチベーション ネストした構造に対するcopy メソッドのネスト地獄 様々なデータを共通のインターフェースで操作できる 非侵入的に外側から追加できる 特定のアーキテクチャに依存しない概念 汎用的に使える などなど
  5. 5. Lens って何? getter/setter を抽象的にしたもの purely functional reference
  6. 6. 実は 余状態コモナド余代数 (Costate Comonad Coalgebra)
  7. 7. getter/setter ってなんだっけ? (広く一般的な意味で)オブジェクト指向言語におい て、あるfield の値を取得するメソッドがgetter で、 field に値をセットするのがsetter。(広く一般的な意味で) クラスのメソッドとして定義され、getFoo、setFoo と名 付けられる事が多い、おなじみの例のアレ。
  8. 8. getter/setter 再考 特定のclass に依存しない、汎用的な関数と捉えてみる
  9. 9. getter の仕事とは オブジェクトからある値を取り出す 素直にシグネチャとして表してみると… オブジェクトS からある値A を取り出す S => A // getter def get[S, A]: S => A
  10. 10. setter の仕事とは オブジェクトの一部をある値に変更する 素直にシグネチャとして表してみると… オブジェクトS の一部をある値A に変更する S => A => S // setter def set[S, A]: S => A => S
  11. 11. あるオブジェクトS の各field に対して前述のような getter/setter が存在した時、 それらを使って汎用的な get/set メソッドの提供を考える。 ↓↓↓ その仕組みを実現するものをLens と呼ぶ。
  12. 12. get/set Lens class Lens[S, A]( getter: S => A, setter: S => A => S ) { def get(s: S): A = getter(s) def set(s: S, a: A): S = setter(s)(a) def modify(s: S, f: A => A): S = set(s, f(get(s))) }
  13. 13. get/set Lens getter/setter をコンストラクタの引数として与える。 class Lens[S, A]( getter: S => A, setter: S => A => S ) {
  14. 14. Lens の値を定義する case class User(id: Int, name: String) // User#id 対 Lens val _id = new Lens[User, Int]( _.id, // getter user => newId => user.copy(id = newId) // setter ) // User#name 対 Lens val _name = new Lens[User, String]( _.name, // getter user => newName => user.copy(name = newName) // setter )
  15. 15. 使い方 val user1 = User(100, "John Doe") _id.get(user1) // res: Int = 100 _name.get(user1) // res: String = John Doe _name.set(user1, "Naoki Aoyama") // res: User = User(100,Naoki Aoyama) _name.modify(user1, _.toUpperCase) // res: User = User(100,JOHN DOE)
  16. 16. Lens Laws Lens には満たすべき法則がある。 get/set set(s, get(s)) == s set/get get(set(s, a)) == a set/set set(set(s, a1), a2) == set(s, a2)
  17. 17. ネストしたデータが対象の時は? ネストした構造に対するcopy メソッドのネスト地獄を どう解決するか。
  18. 18. Lens の合成を考える class Lens[S, A](getter: S => A, setter: S => A => S) { def get(s: S): A = getter(s) def set(s: S, a: A): S = setter(s)(a) def modify(s: S, f: A => A): S = set(s, f(get(s))) def ^|->[B](other: Lens[A, B]): Lens[S, B] = new Lens( s => other.get(this.get(s)), // getter s => b => this.set(s, other.set(this.get(s), b)) //setter ) }
  19. 19. Lens の合成を考える def ^|->[B](other: Lens[A, B]): Lens[S, B] = new Lens( s => other.get(this.get(s)), // getter s => b => this.set(s, other.set(this.get(s), b)) //setter )
  20. 20. 試してみよう case class Message(user: User, body: String) // Message#id 対 Lens val _body = ... // Message#user 対 Lens val _user: Lens[Message, User] = new Lens( _.user, message => newUser => message.copy(user = newUser) )
  21. 21. Before val message = Message(User(100, "John Doe"), "Hello") message.user // res: User = User(100,John Doe) message.user.name // res: String = John Doe message.copy( user = user.copy( name = "aoino" ) ) // res: Message = Message(User(100,aoino), Hello) message.copy( user = user.copy( name = message.user.name.toUpperCase ) ) // res: Message = Message(User(100,JOHN DOE),Hello)
  22. 22. A er val message = Message(User(100, "John Doe"), "Hello") _user.get(message) // res: User = User(100,John Doe) (_user ^|-> _name).get(message) // res: String = John Doe (_user ^|-> _name).set(message, "aoino") // res: Message = Message(User(100,aoino),Hello) (_user ^|-> _name).modify(message, _.toUpperCase) // res: Message = Message(User(100,JOHN DOE),Hello)
  23. 23. ところで
  24. 24. オブジェクトS にOption 型のfield が存在する場合に get メソッドが適切に定義できるだろうか?
  25. 25. A == Option[B] となるようなLens を考えてみる。 class Lens[S, A]( getter: S => A, setter: S => A => S ) { // ... }
  26. 26. すると、A がOption[B] となるような場合に get メソッドが実装出来ない。 class BadLens[S, B]( getter: S => B, setter: S => B => S ) { def get(s: S): B = getter(s) match { case Some(b) => b case None => ??? /// 何 返 } /// ... }
  27. 27. ここで、Prism を導入する。
  28. 28. getter の取りうる引数に対して setter が返すことが可能な値が足りない場合に Lens だけではカバーしきれない。 ↓↓↓ その仕組みを実現するものをPrism と呼ぶ。
  29. 29. Prism class Prism[S, A]( _getOption: S => Option[A], _reverseGet: A => S ) { def getOption(s: S): Option[A] = _getOption(s) def reverseGet(a: A): S = _reverseGet(a) }
  30. 30. まずは、Some, None に対するPrism を定義する。 // Some 対 Prism def _some[A] = new Prism[Option[A], A]( { case Some(a) => Some(a); case None => None }, Some.apply ) // None 対 Prism def _none[A] = new Prism[Option[A], Unit]( { case None => Some(()); case Some(_) => None }, _ => None )
  31. 31. 一部のユーザーにEmail アドレスの情報を 持たせたくなった場合を想定する。 case class User(id: Int, name: String, email: Option[String]) // User#email 対 Prism val _email = new Lens[User, Option[String]]( _.email, user => newEmail => user.copy(email = newEmail) )
  32. 32. _some.getOption(_email.get(User(1, "aaa", Option("email")))) // res: Option[String] = Some(email) _some.getOption(_email.get(User(1, "aaa", None))) // res: Option[String] = None
  33. 33. とてもダサい!!
  34. 34. _email.get, _some.getOption を直接呼び出している コードの見通しが悪い getOption の内部がより複雑だった場合
  35. 35. Lens の時と同じように合成を考えれば良い。
  36. 36. Q: Lens とPrism を合成すると何になる? Lens Prism その他
  37. 37. A: Optional
  38. 38. Optics Hierarchie (Monocle) ref. Monocle の よりREADME.md
  39. 39. Optics Hierarchie (lens) ref. lens の よりREADME.md
  40. 40. Optional はLens とPrism の両方の性質を持つOptics ※ 下記コードはMonocle の よりOptional.scala object Optional { def apply[S, A](_getOption: S => Option[A])(_set: A => S => S): Optional new Optional[S, A]{ // ... } }
  41. 41. Monocle を使って書くと以下の通り。 val user = User(1, "aaa", Some("email")) (_email composePrism _some).getOption(user) // res: String = email 様々な合成メソッドのエイリアスが 記号として提供されている。 (_email ^<-? _some).getOption(user) // res: String = email
  42. 42. \( 'ω')/ウオオオオオアアアーーーッ!
  43. 43. ^|->> ^|-? ^<-? ^|-> ^<->
  44. 44. \(՞‫)◔ةڼ‬/ウオオオオオアアアーーーッ!?!?!?
  45. 45. ここまでのまとめ Lens/Prism の概念と使い方を理解した Optics Hierarchie を知った
  46. 46. Lens の種類
  47. 47. Lens にはコンセプトや実装に応じていくつか種類がある get/set lens get/modify lens Iso lens Store Comonad Lens van Laarhoven lens and so on ...
  48. 48. van Laarhoven Lens
  49. 49. van Laarhoven Lens とは? 2009 年7 月にTwan van Laarhoven さんが書いた の アイディアが元になったLens で、Haskell の やScala の のコンセプトの基礎になってる。 blog lens Monocle
  50. 50. def Lens[S, A, F[_]: Functor] = S => (A => F[A]) => F[S]
  51. 51. type Lens s a = forall f. Functor f => (a -> f a) -> s -> f s
  52. 52. 閑話休題
  53. 53. traverse 関数はご存知ですか? def traverse[G[_]: Applicative, A, B](fa: F[A])(f: A => G[B]): G[F[B]]
  54. 54. 例えば、F をList、G をOption とすると、traverse 関数は リスト内の値にf を適用し、全てSome だった場合には f の適用結果をSome に包んで返し 一つでもNone の場合はNone を返します。 def isEven(v: Int): Option[Int] = if (v % 2 == 0) Some(v) else None List(2, 4, 5).traverse(isEven) // res: Option[List[Int]] = None List(2, 4, 6).traverse(isEven) // res: Option[List[Int]] = Some(List(2, 4, 6)) ※ 上記コードはScalaz を使用しています。
  55. 55. 閑話休題おわり
  56. 56. 理解する為にgetter/setter を再考してみよう。
  57. 57. setter の再考
  58. 58. setter の再考 冒頭に出てきたsetter の型は以下の通り。 def setter: S => A => S これはmodify メソッドの特殊形と考えられる。 なので、modify のsignature を取り入れて def setter: S => (A => A) => S と、改めて定義する。
  59. 59. この型に見覚えない?
  60. 60. trait Functor[F[_]] { // F[A] => (A => B) => F[B] def map[A, B](fa: F[A])(f: A => B): F[B] }
  61. 61. つまり、我々はset/modify をするのに各field に対する Functor#map が欲しいのだ。
  62. 62. しかし、Functor のinstance をclass のfield 毎にそれぞれ 定義することは現実的ではない...
  63. 63. Functor#map はTraverse#traverse で定義できる trait Traverse[F[_]] extends Functor[F] { // F[A] => (A => G[B]) => G[F[B]] def traverse[G[_]: Applicative, A, B](fa: F[A])(f: A => G[B]): G[F[B type Id[A] = A // Id Applicative instance 自明 implicit def idApplicative[A] = new Applicative[Id] { ... } // F[A] => (A => Id[B]) => Id[F[B]] def map[A, B](fa: F[A])(f: A => B): F[B] = traverse[Id, A, B](fa)(f) }
  64. 64. つまり、このtraverse の部分を同等な関数に置き換える ことで、Functor#map のような関数を得られる。この F[A], F[B] をS と置いてSetter という名前をつけよう。 type Setter[S, A] = S => (A => Id[A]) => Id[S] このSetter[S, A] を用いてset/modify メソッドが作れる。 // Setter[S, A] => S => (A => A) => S def modify[S, A](setter: Setter[S, A])(s: S)(f: A => A): S = setter(s)(a => (f(a): Id[A])) // Setter[S, A] => S => A => S def set[S, A](setter: Setter[S, A])(s: S)(a: A): S = setter(s)(_ => (a: Id[A]))
  65. 65. 動作確認 val _id: Setter[User, Int] = (user: User) => (f: Int => Id[Int]) => user.copy(id = f(u.id)) scala> modify(_name)(User(100, "John Doe"))(_.toUpperCase) // res: User = User(100,JOHN DOE) scala> set(_name)(User(100, "John Doe"))("aoiroaoino") // res: User = User(100,aoiroaoino) \( 'ω')/ウオオオオオアアアーーーッ!
  66. 66. getter の再考
  67. 67. getter の再考 冒頭に出てきたgetter の型は以下の通り。 def getter: S => A 取得するだけでなく、関数を適用した結果を返すように def getter: S => (A => A) => A と、改めて定義する。
  68. 68. この型に見覚えない?
  69. 69. trait Foldable[F[_]] { // F[A] => (A => B) => B def foldMap[A, B](fa: F[A])(f: A => B)(implicit mb: Monoid[B]): B }
  70. 70. つまり、我々はget をするのに各field に対する Foldable#foldMap が欲しいのだ。
  71. 71. しかし、Foldable のinstance をclass のfield 毎にそれぞ れ定義することは現実的ではない...
  72. 72. Foldable#foldMap はTraverse#traverse で定義できる trait Traverse[F[_]] extends Functor[F] { // F[A] => (A => G[B]) => G[F[B]] def traverse[G[_]: Applicative, A, B](fa: F[A])(f: A => G[B]): G[F[B // Const Applicative instance 自明 case class Const[A, B](runConst: A) implicit def monoidApplicative[A](A: Monoid[A]) = new Applicative[({type λ[X] = Const[A, X]})#λ] { ... } // F[A] => (A => B) => B def foldMap[A, B](fa: F[A])(f: A => B)(implicit mb: Monoid[B]): B = traverse[({type λ[X] = Const[B, X]})#λ, A, Nothing](fa)(f) }
  73. 73. Setter と同様にtraverse の部分を同等な関数に置き換え ることで、Foldable#foldMap のような関数を得られる。 このF[A] をS と置いてGetter という名前をつけよう。 type Getting[R, S, A] = S => (A => Const[R, A]) => Const[R, S] // S => (A => Const[A, A]) => Const[A, S] type Getter[S, A] = Getting[A, S, A] このGetter[S, A] を用いてget メソッドが作れる。 // Getter[S, A] => S => A def get[S, A](getter: Getter[S, A])(s: S): A = getter(s)(a => Const(a)).runConst
  74. 74. さて、我々は似たようなsignature を持つGetter/Setter を 手に入れた。これらを並べて見てみよう。 type Setter[S, A] = S => (A => Id[A]) => Id[S] type Getter[S, A] = S => (A => Const[A, A]) => Const[A, S] Const とId の部分をFunctor のinstance を要求する型変 数に置き換えられそう。
  75. 75. これでvan Laarhoven lens の定義を理解できましたね? def Lens[S, A, F[_]: Functor] = S => (A => F[A]) => F[S]
  76. 76. type Lens s a = forall f. Functor f => (a -> f a) -> s -> f s
  77. 77. しかし、ここで一つ疑問が湧きませんか?
  78. 78. Q: van Laarhoven lens はうまく合成できるのだろうか?
  79. 79. Getter もSetter も中身はtraverse と同等の関数ですね。 なので、代表してtraverse の合成を見てみましょう。
  80. 80. f にId/Const が入ります。 構造のネストする順番と合成 の順序が一致し、左から右へと辿れますね。 traverse :: (Applicative f, Traversable t) => (a -> f b) -> t a -> f (t b) traverse . traverse :: (Applicative f, Traversable t, Traversable t1) => (a -> f b) -> t (t1 a) -> f (t (t1 b)) traverse . traverse . traverse :: (Applicative f, Traversable t, Traversable t1, Traversable t2) => (a -> f b) -> t (t1 (t2 a)) -> f (t (t1 (t2 b))) おやおや?このHaskell の関数合成に使う(.) 演算子が、 Scala やJava などの(.) 演算子に見えませんか?
  81. 81. Haskell でvan Laarhoven Lens の合成はこう書ける。 ghci> set (_2 . _1) 42 ("hello",("world","!!!")) ("hello",(42,"!!!"))
  82. 82. A: Haskell だと超美しく合成できる...
  83. 83. まとめ Lens/Prism の概念と使い方を完全マスターした Optics Hierarchie と呼ばれる階層が存在する Lens には種類がある van Laarhoven lens はやばい

×