2015-06-02 32 views
13

Başımı State monad'ın etrafına doyorum. Önemsiz örnekler anlamak kolaydır. Artık alan nesnelerinin kompozit olduğu gerçek bir dünyaya geçiyorum. Örneğin, aşağıdaki alanı nesneleri (onlar çok mantıklı, sırf örnek yapmazlar) ile:Scala State monad - farklı durum türlerini birleştiriyor

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

State[S, +A] monad içinde WorkerS olarak türlerini dikkate alındığında bu gibi birkaç combinators yazmak için oldukça kolaydır:

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. 

Bunları Master durum kombinatorörleri ile birleştirmenin deyimsel yolu nedir? Örneğin.

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

ben şöyle uygulayabilirsiniz:

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

Ne sevmiyorum ben manuel geçen transformatör içindeki Devlet monad çalıştırmak zorunda olmasıdır. Gerçek dünya örneğim biraz daha ilgili. Bu yaklaşımla, hızla dağınık hale gelir.

Bu tür artımlı güncelleştirmeleri çalıştırmak için daha fazla deyim var mı?

+0

Güzel soru! Scalaz gibi bazı somut “Devlet” uygulamalarına mı atıf yapıyorsunuz? – Odomontois

+0

Kesinlikle 'LensT' kullanımı için güzel bir örnek gibi görünüyor, bazı uzmanların cevabını görmek için sabırsızlanıyorum. – Odomontois

cevap

8

Bu lensleri ve devlet monadını birleştirerek oldukça hoş bir şekilde yapılabilir.

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) 
: bize Master içine bakmak için izin genel amaçlı lens birkaç şimdi

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 

Ve: İlk kurulum için (ben senin hafifçe o Scalaz 7.1 ile derlemeye almak için kaydetmiştiniz)

sonra temelde bitti:

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

İşte %%= sadece biz uygun worke için yakınlaştırılmış bir kez gerçekleştirilecek devlet operasyonu söyler objektifimiz üzerinden.

+0

Kendi fakir adamın monad uygulamalarını çalıştırıyorum. Bunu anlamak için Lens'in uygulanması ve Lens ile Devlet entegrasyonuna (özellikle de %% = işlem) ihtiyacım olduğunu anlıyor muyum? –

+0

Ayrıca Scalaz vs monadların elle yazılmış uygulamalarını kullanmaya ne dersiniz? –

+0

Eğer bu tür bir şey yapıyorsanız, Scalaz veya kedileri kendi yerinizi yuvarlamak yerine kullanmanızı şiddetle tavsiye ederim. –

İlgili konular