この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
はじめに
monocle でOptionを含むcase classの操作をするときの合成をよく忘れるのでそのメモです。
例
ネストしたOptionの内側の変更をする2パターンの例を示します。
- 外側のOptionがないとき、外側の値を作ってから内側の値を操作する
- 外側のOptionがあるときだけ、内側の値を操作する
パターン2はそれぞれの階層におけるlensを作っておいて合成することもできます。
コード
import monocle.macros.GenLens
import monocle._
import Monocle._
import cats.implicits._
import monocle.macros.syntax.lens._
object LensExample extends App {
final case class Root(node: Option[Node])
final case class Node(name: Option[String])
//Root以下のNodeに名前をセットする。Nodeがなければ空のノードをセットする
println(Root(None).lens(_.node).modify(_.getOrElse(Node(None)).lens(_.name).set("New Name".some).some))
//Root以下のNodeに名前をセットする。Nodeがなければセットしない
//Nodeがない時
println(Root(None) &|-> GenLens[Root](_.node) ^<-? some ^|-> GenLens[Node](_.name) set "New Name".some)
//Nodeがある時
println(Root(Node(None).some) &|-> GenLens[Root](_.node) ^<-? some ^|-> GenLens[Node](_.name) set "New Name".some)
//nameを変更
println(
Root(Node("name".some).some) &|-> GenLens[Root](_.node) ^<-? some ^|-> GenLens[Node](_.name) modify (_.map(
_.toUpperCase)))
}
実行結果
//Root以下のNodeに名前をセットする。Nodeがなければ空のノードをセットする
Root(Some(Node(Some(New Name))))
//Root以下のNodeに名前をセットする。Nodeがなければセットしない
//Nodeがない時
Root(None)
//Nodeがある時
Root(Some(Node(Some(New Name))))
//nameを変更
Root(Some(Node(Some(NAME))))
Process finished with exit code 0