13. 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)))
}
19. 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
)
}
20. 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
)
21. 試してみよう
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)
)
22. 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)
23. 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)
26. A == Option[B] となるようなLens を考えてみる。
class Lens[S, A](
getter: S => A,
setter: S => A => S
) {
// ...
}
27. すると、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 => ??? /// 何 返
}
/// ...
}
60. setter の再考
冒頭に出てきたsetter の型は以下の通り。
def setter: S => A => S
これはmodify メソッドの特殊形と考えられる。
なので、modify のsignature を取り入れて
def setter: S => (A => A) => S
と、改めて定義する。
82. 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 などの(.) 演算子に見えませんか?