2015-06-02 15 views
13

Tôi đang bao quanh đầu của mình xung quanh đơn vị tiểu bang. Các ví dụ tầm thường dễ hiểu. Bây giờ tôi đang chuyển sang một trường hợp thế giới thực, nơi các đối tượng miền được tổng hợp. Ví dụ, với các đối tượng miền sau (họ không có ý nghĩa nhiều, chỉ cần tuyệt ví dụ):Đơn vị tiểu bang Scala - kết hợp các loại trạng thái khác nhau

case class Master(workers: Map[String, Worker]) 
case class Worker(elapsed: Long, result: Vector[String]) 
case class Message(workerId: String, work: String, elapsed: Long) 

Xét Worker như S loại trong State[S, +A] đơn nguyên nó khá dễ dàng để viết một vài combinators như thế này:

type WorkerState[+A] = State[Worker, A] 
def update(message: Message): WorkerState[Unit] = State.modify { w => 
    w.copy(elapsed = w.elapsed + message.elapsed, 
      result = w.result :+ message.work) 
} 
def getWork: WorkerState[Vector[String]] = State { w => (w.result, w) } 
def getElapsed: WorkerState[Long] = State { w => (w.elapsed, w) } 
def updateAndGetElapsed(message: Message): WorkerState[Long] = for { 
    _ <- update(message) 
    elapsed <- getElapsed 
} yield elapsed 
// etc. 

Cách thành ngữ để kết hợp chúng với bộ kết hợp trạng thái Master là gì? ví dụ.

type MasterState[+A] = State[Master, A] 
def updateAndGetElapsedTime(message: Message): MasterState[Option[Long]] 

tôi có thể thực hiện điều này như sau:

def updateAndGetElapsedTime(message: Message): MasterState[Option[Long]] = 
    State { m => 
     m.workers.get(message.workerId) match { 
      case None => (None, m) 
      case Some(w) => 
       val (t, newW) = updateAndGetElapsed(message).run(w) 
       (Some(t), m.copy(m.workers.updated(message.workerId, newW)) 
     } 
    } 

Những gì tôi không thích là tôi phải tự chạy đơn nguyên nhà nước bên trong máy biến áp ngoái. Ví dụ thế giới thực của tôi có liên quan nhiều hơn một chút. Với cách tiếp cận này, nó nhanh chóng bị lộn xộn.

Có cách nào thành ngữ hơn để chạy loại cập nhật gia tăng này không?

+0

Câu hỏi hay! Bạn đang đề cập đến một số thực hiện cụ thể 'State' như' scalaz'? – Odomontois

+0

Nó chắc chắn trông giống như ví dụ tốt đẹp cho sử dụng 'LensT', không thể chờ đợi để xem một số câu trả lời của chuyên gia. – Odomontois

Trả lời

8

Có thể thực hiện điều này khá độc đáo bằng cách kết hợp ống kính và đơn vị trạng thái. Đầu tiên cho việc cài đặt (Tôi đã chỉnh sửa của bạn nhẹ nhàng để có được nó để biên dịch với Scalaz 7.1):

case class Master(workers: Map[String, Worker]) 
case class Worker(elapsed: Long, result: Vector[String]) 
case class Message(workerId: String, work: String, elapsed: Long) 

import scalaz._, Scalaz._ 

type WorkerState[A] = State[Worker, A] 

def update(message: Message): WorkerState[Unit] = State.modify { w => 
    w.copy(
    elapsed = w.elapsed + message.elapsed, 
    result = w.result :+ message.work 
) 
} 

def getWork: WorkerState[Vector[String]] = State.gets(_.result) 
def getElapsed: WorkerState[Long] = State.gets(_.elapsed) 
def updateAndGetElapsed(message: Message): WorkerState[Long] = for { 
    _ <- update(message) 
    elapsed <- getElapsed 
} yield elapsed 

Và bây giờ cho một vài ống kính mục đích chung đó cho phép chúng ta nhìn vào bên trong một Master:

val workersLens: Lens[Master, Map[String, Worker]] = Lens.lensu(
    (m, ws) => m.copy(workers = ws), 
    _.workers 
) 

def workerLens(workerId: String): PLens[Master, Worker] = 
    workersLens.partial andThen PLens.mapVPLens(workerId) 

Và sau đó chúng ta về cơ bản thực hiện:

def updateAndGetElapsedTime(message: Message): State[Master, Option[Long]] = 
    workerLens(message.workerId) %%= updateAndGetElapsed(message) 

ở đây %%= chỉ cho chúng ta biết những gì hoạt động nhà nước để thực hiện khi chúng tôi đã được zoom đến worke thích hợp r qua ống kính của chúng tôi.

+0

Tôi đang chạy các triển khai đơn lẻ của người đàn ông nghèo của riêng tôi. Tôi có hiểu nó một cách đúng đắn rằng để có được điều này làm việc tôi cần một thực hiện của ống kính và tích hợp của nhà nước với ống kính (đặc biệt là %% = hoạt động)? –

+0

Ngoài ra, việc bạn sử dụng Scalaz so với việc thực hiện viết tay của monads là gì? –

+0

Nếu bạn đang làm điều này, tôi khuyên bạn nên sử dụng Scalaz hoặc mèo thay vì tự mình lăn. –

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