独学大学情報学部

ただのノート。主にプログラミング。

MonocleのapplyLensメソッドの使い方

去年末くらいからぼちぼち触り始めてたけど今更知った。

使い方

例えばこんな感じのデータ構造(とLens)が定義されてるとして、*1

@Lenses case class Address(street: String, postalCode: String)
@Lenses case class User(name: String, age: Int, address: Address)

Lensを合成していってgetしたり、modifyしたりするわけですが、

import monocle.syntax.apply._
import Address._, User._ // 生成されたLensの為に

val me = User("Aoino", 24, Address("street", "xxx-xxxx"))

scala> address composeLens street get me
res1: String = street

// ^|-> はcomposeLensのエイリアスメソッド
scala> (address ^|-> street).modify(_.capitalize)(me)
res8: User = User(Aoino,24,Address(Street,xxx-xxxx))

applyLensを使うと以下のようにかけます。

scala> me applyLens address composeLens street get
res13: String = street

// &|-> applyLensのエイリアスメソッド
scala> me &|-> address ^|-> street modify(_.capitalize)
res16: User = User(Aoino,24,Address(Street,xxx-xxxx))

使わなかった時よりも若干見やすく、流れるようなインターフェース感()が増しましたね。おつおつ。

実装

単純に暗黙的変換でメソッドが追加されてる(ように見える)だけです。

https://github.com/julien-truffaut/Monocle/blob/v1.1.1/core/src/main/scala/monocle/syntax/Apply.scala#L10-L19

ちなみに

タイトルにはapplyLensって書いてますが、ほかにも以下のメソッド共が存在します。

method aliase
applyTraversal &|->>
applyOptional &|-?
applyPrism &<-?
applyLens &|->
applyIso &<->

で、一応composeXXXもまとめると

method aliase
composeTraversal ^|->>
composeOptional ^|-?
composePrism ^<-?
composeLens ^|->
composeIso ^<->

初見は「はぁ???」ってなりますが、composeと一緒に眺めると&か^の違いしかないので、覚えるのはそんなに苦労しないんじゃないかと。*2

まとめ

ってなわけで、これでますますScalaでLens欲が高まりますね!!

*1:マクロアノテーションの力により、コンパニオンオブジェクト内にcase classで定義されてるフィールド名と同名のLensが定義されます。詳しくはこちら

*2:とはいえ、右手onlyで打つ記号共なので逆に打ちにくいっていう