加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

Scala状态monad – 结合不同的状态类型

发布时间:2020-12-16 09:16:16 所属栏目:安全 来源:网络整理
导读:我正在包围我的头围绕州monad.简单的例子很容易理解.我现在正在移动到一个现实世界的情况下,域对象是复合的.例如,使用以下域对象(它们没有什么意义,只是纯粹的例子): case class Master(workers: Map[String,Worker])case class Worker(elapsed: Long,resul
我正在包围我的头围绕州monad.简单的例子很容易理解.我现在正在移动到一个现实世界的情况下,域对象是复合的.例如,使用以下域对象(它们没有什么意义,只是纯粹的例子):

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

考虑到工人作为S类型的国家[S,A] monad很容易写出一些组合者,如下所示:

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.

将这些与主状态组合器相结合的惯用方法是什么?例如

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

我可以这样实现:

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

我不喜欢的是我必须在最后一个变压器内手动运行状态monad.我的现实世界的例子有更多的参与.通过这种方法,它很快就会变得凌乱.

有更多惯用的方式来运行这种增量更新吗?

解决方法

通过组合镜头和状态monad可以很好地做到这一点.首先为安装程序(我已经编辑你的轻轻地让它编译与Scalaz 7.1):

case class Master(workers: Map[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

而现在的几个通用镜头,让我们看看一个硕士:

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)

然后我们基本完成了:

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

在这里,%% =只是告诉我们,一旦我们通过我们的镜头放大到适当的工作人员,我们将执行什么状态操作.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读