scala - 在深度复制到 Map 值时避免重复使用镜头

标签 scala scalaz lenses

我有一个不可变的数据结构,我在 Maps 中嵌套了值,如下所示:

case class TradingDay(syms: Map[String, SymDay] = Map.empty)
case class SymDay(sym: String, traders: Map[String, TraderSymDay] = Map.empty)
case class TraderSymDay(trader: String, sym: String, trades: List[Trade] = Nil)

另外,我有一个当天所有交易的列表,我想生成 TradingDay结构,其中
case class Trade(sym: String, trader: String, qty: Int)

我试图弄清楚如何通过折叠我的交易来使用镜头更新这个结构(见附录):
(TradingDay() /: trades) { (trd, d) =>
  def sym = trd.sym
  def trader = trd.trader
  import TradingDay._
  import SymDay._
  import TraderSymDay._
  val mod =
    for {
      _ <- (Syms member sym).mods(
             _ orElse some(SymDay(sym)))
      _ <- (Syms at sym andThen Traders member trader).mods(
             _ orElse some(TraderSymDay(trader, sym)))
      _ <- (Syms at sym andThen (Traders at trader) andThen Trades).mods(
             trd :: _)
      x <- init
    } yield x
  mod ! d
}

这有效;但我想知道我是否可以减少重复(在添加到 map 然后修改 map 键处的值方面。它似乎并不比相关的深层复制更烦人。

附录 - 镜片
object TradingDay {
  val Syms = Lens[TradingDay, Map[String, SymDay]](_.syms, (d, s) => d.copy(syms = s))
}

object SymDay {
  val Traders = Lens[SymDay, Map[String, TraderSymDay]](_.traders, (d, t) => d.copy(traders = t))
}

object TraderSymDay  {
   val Trades = Lens[TraderSymDay, List[Trade]](_.trades, (d, f) => d.copy(trades = f))
}

最佳答案


type @>[A,B] = Lens[A, B]

并通过保持这个镜头
val Syms : Lens[TradingDay, Map[String, SymDay]]

并定义这些镜头:
val F : Map[String, SymDay] @> Option[SymDay] = ...
val G : Option[SymDay] @> Map[String, TraderSymDay] = ...
val H : Map[String, TraderSymDay] @> Option[TraderSymDay] = ...
val I : Option[TraderSymDay] @> List[Trade] = ...

val J: TradingDay @> List[Trade] = Syms >=> F >=> G >=> H >=> I

你可以得到这个:
(trades /: TradingDay()){ (trd, d) => (J.map(trd :: _).flatMap(_ => init)) ! d }

关于scala - 在深度复制到 Map 值时避免重复使用镜头,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10245904/

相关文章:

scala - 如何在Scala控制台中使用宏?

haskell - 将 setter/getter 组合成折叠

scala - 将 (A => (M[B], M[C])) 转换为 (A => M[(B, C)])

scala - 如何帮助 Scalaz 进行类型推断和 2 个类型参数

scala - 如何将 Kleisli 组合与返回验证的函数一起使用?

scala - 镜头和部分镜头有什么区别?

haskell - 为列表创建一个镜头(类似)

json - Spark 如何在 Scala 的两个 JSONS 中更改键的数量?

scala - 从分区的 Parquet 文件读取DataFrame

scala - 在 Spark 中写入和读取原始字节数组 - 使用序列文件 SequenceFile