質問にはデータの変更については触れられていませんでしたが、これを行う必要がある場合、Scalaライブラリにはこれを簡単にするツールがないことがすぐにわかります(データが不変の場合)。これをまだ経験していない場合は、質問で定義されたタイプを使用して、によって保持されているvalue
のを置き換える、または変更する関数を作成してみてください。Cash
Person
Tony MorrisのScalaの非対称レンズで説明されているように、レンズはこの問題の適切な解決策です。
これは、Scalazのscalaz-sevenブランチからのおよび(部分レンズ)実装を使用してvalue
、人のにアクセスして更新する方法の例です。Cash
Lens
PLens
まず、いくつかの定型文:ケースクラスの各フィールドのLensインスタンスを定義します。A @-@ B
と同じ意味Lens[A, B]
です。
val pants: Person @-@ Option[Pants] =
lensG(_.pants, p => ps => p.copy(pants = ps))
val pocket: Pants @-@ Option[Pocket] =
lensG(_.pocket, ps => p => ps.copy(pocket = p))
val cash: Pocket @-@ Option[Cash] =
lensG(_.cash, p => c => p.copy(cash = c))
val value: Cash @-@ String =
lensG(_.value, c => v => c.copy(value = v))
ただし、ほとんどのフィールドがOption
タイプでラップされているため、これらのレンズのすべてを構成することはできません。
救助のための部分レンズ:これらにより、の値やの値など、存在しない可能性のある構造の部分にアクセスして更新することができます。Some
Option
head
List
somePLens
Scalaz 7の機能を使用して、各オプションフィールドを表示する部分レンズを作成できます。ただし、通常のレンズの1つで部分レンズを構成するには、partial
すべてに存在する方法を使用して、通常のレンズと同等の部分レンズインスタンスにアクセスする必要がありますLens
。
// @-? is an infix type alias for PLens
val someCash: Pocket @-? Cash = cash.partial andThen somePLens
scala> someCash.get(Pocket(Some(Cash("zilch"))))
res1: Option[Cash] = Some(Cash(zilch))
Person
同様に、すべてのレンズのpartial
インスタンスを構成し、のインスタンスをサンドイッチすることで、が保有する現金を表示する部分レンズを作成できますsomePLens
。ここでは<=<
、のエイリアスである演算子を使用しました(これは、オペランドを切り替えたandThen
場合と同等です)。compose
val someCashValue: Person @-? String =
pants.partial <=< somePLens <=<
pocket.partial <=< somePLens <=<
cash.partial <=< somePLens <=<
value.partial
Person
遊ぶインスタンスの作成:
val ben = Person(Some(Pants(Some(Pocket(Some(Cash("zilch")))))))
部分レンズを使用して、私が持っている現金の価値にアクセスします。
scala> someCashValue.get(ben)
res2: Option[String] = Some(zilch)
部分レンズを使用して値を変更する:
scala> someCashValue.mod(_ + ", zero, nada", ben)
res3: Person = Person(Some(Pants(Some(Pocket(Some(Cash(zilch, zero, nada)))))))
これで、ズボンを着用していない場合(!)、現金の価値を変更しようとしても効果がないことがわかります。
scala> val ben = Person(None)
ben: Person = Person(None)
scala> someCashValue.mod(_ + ", zero, nada", ben)
res4: Person = Person(None)