2012-04-20 19 views
14

Tôi có một cấu trúc dữ liệu không thay đổi nơi tôi đã lồng giá trị trong Maps, như vậy:Tránh lặp lại sử dụng ống kính trong khi sâu sao chép vào Bản đồ giá trị

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) 

riêng tôi có một danh sách của tất cả các ngành nghề trong ngày, và tôi muốn tạo ra cấu trúc TradingDay, nơi

case class Trade(sym: String, trader: String, qty: Int) 

tôi đang cố gắng tìm ra làm thế nào tôi sẽ cập nhật cấu trúc này với ống kính (xem phụ lục) bằng cách gấp qua các giao dịch của tôi:

(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 
} 

này hoạt động; nhưng tôi tự hỏi liệu tôi có thể ít lặp đi lặp lại (về thêm vào bản đồ và sau đó thay đổi giá trị tại các trọng điểm của bản đồ. Nó dường như không phải là ít nhiều gây phiền nhiễu hơn so với sâu bản liên quan.

Phụ lục - các ống kính

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)) 
} 
+3

+1 cho một câu hỏi với một phụ lục – ziggystar

Trả lời

0

trả lời được cung cấp bởi Jordan Tây (@_jrwest)

Đó chỉ là một thay đổi nhỏ và liên quan giới thiệu chuyển đổi sau:

implicit def myMapLens[S,K,V] = MyMapLens[S,K,V](_) 
case class MyMapLens[S,K,V](lens: Lens[S,Map[K,V]]) { 
    def putIfAbsent(k: K, v: => V) 
    = lens.mods(m => m get k map (_ => m) getOrElse (m + (k -> v))) 
} 

Sau đó, chúng ta có thể sử dụng điều này như sau:

(TradingDay() /: trades) { (d, trade) => 
    def sym = trade.sym 
    def trader = trade.trader 
    def traders = Syms at sym andThen Traders 
    def trades = Syms at sym andThen (Traders at trader) andThen Trades 
    val upd = 
    for { 
     _ <- Syms putIfAbsent (sym, SymDay(sym)) 
     _ <- traders putIfAbsent (trader, TraderSymDay(trader, sym)) 
     _ <- trades.mods(trade :: _) 
    } yield() 
    upd ~> d 
} 
+1

Đã có chuyển đổi tiềm ẩn như vậy trong codebase Scalaz. Chỉ putIfAbsent bị thiếu. Chăm sóc cho một yêu cầu kéo? –

6

với

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

và bằng cách giữ cho ống kính này

val Syms : Lens[TradingDay, Map[String, SymDay]] 

và xác định những ống kính:

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 

bạn có thể có được điều này:

(trades /: TradingDay()){ (trd, d) => (J.map(trd :: _).flatMap(_ => init)) ! d } 
+0

Tôi đang bối rối về cách mà có thể làm việc; bản đồ bên trong được thêm vào đâu? Ví dụ; việc thực hiện rõ ràng 'G' sẽ trả về một bản đồ trống cho' None'. Bất kỳ cơ hội nào của bạn có thể đưa ra điều này để chứng minh nó hoạt động? –

+0

Chắc chắn. BTW, có vẻ như bạn đang dựa nhiều hơn vào trạng thái đơn thuần hơn Lens. Ống kính rất tốt khi truy cập các thuộc tính lồng nhau của các kiểu dữ liệu đại số. Các truy cập đó không phụ thuộc vào trạng thái bên ngoài. –

Các vấn đề liên quan