首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ReaderWriterState[Either]短路

ReaderWriterState[Either]短路
EN

Stack Overflow用户
提问于 2017-07-20 14:54:14
回答 2查看 186关注 0票数 1

我正在开发一个游戏原型,并试图尽可能地保持纯正。所有用例都适合于一个场景-

  1. 试着在储藏室里找到玩家
  2. 执行一些业务逻辑
  3. 更新存储中的播放机
  4. 当更新时,一个可以产生一些输出-日志消息,消息给另一个玩家,等等。

另一方面,我们必须访问环境(数据库、资源等)、全局游戏状态(不可更改的游戏信任、种子等)。

为了把这一切联系在一起,我最终得到了这样的scalaz7 ReaderWriterState monad:

一些定义:

代码语言:javascript
复制
trait UserService
trait Environment
trait State
sealed trait Error
sealed trait Output

case object GameEnvironment extends Environment
case object GameState extends State
object Output {
  case object Log extends Output
  case object Parcel extends Output
  case object Analytics extends Output
}
object Error {
  case class AppError(code: String) extends Error
  case class ThrowableError(ex: Exception) extends Error
}

服务方法返回类型-通过读取器提供对环境的访问,通过Writer生成一些输出,提供对GameState的访问,并生成方法结果错误或某些类型

代码语言:javascript
复制
type Result[T] = ReaderWriterState[Environment, List[Output], State, Error \/ T]

只是关于如何实现服务的一个例子

代码语言:javascript
复制
object UserServiceImpl extends UserService {
  def findPlayer(id: Long): Result[Player] = ReaderWriterState { (env, state) =>
    (
      Nil, 
      \/-(Player(id, "name")), 
      state
    )
  }
  def updatePlayer(player: Player): Result[Player] = ReaderWriterState { (env, state) =>
    (
      List(Output.Log), 
      \/-(player.copy(name = "updated")), 
      state
    )
  }
}

上面提到的场景是(不编译):

代码语言:javascript
复制
val (out, res, state) = (for {
  playerOrError <- userService.findPlayer(1L)         //How to short-circuit if findPlayer returns left either?
  updated <- userService.updatePlayer(playerOrError)  //How to transform playerOrError to right projection and pass it here?
} yield player).run(GameEnvironment, GameState)

所以,我的问题是:

  1. 如何短路,如果findPlayer:RWS返回左?
  2. 如何将playerOrError转换为右投影并在此传递?

看起来我可以试着用变压器,但我的头也不能绕过去。

谢谢!

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-07-20 19:00:31

使用ReaderWriterStateT

代码语言:javascript
复制
type Result[T] = ReaderWriterStateT[Either[Error, ?], Environment, List[Output], State, T]

这相当于

代码语言:javascript
复制
(Environment, State) => Either[Error, (List[Output], T, State)]

这也意味着在发生错误时,不会写入输出,也不会更改状态。

如果您确实希望保持与您拥有的Result结构相同的结构,请使用

代码语言:javascript
复制
type Result[T] = EitherT[ReaderWriterState[Environment, List[Output], State, ?], Error, T]
票数 1
EN

Stack Overflow用户

发布于 2017-07-27 09:09:27

由于@tomas,它在左侧类型的情况下工作和退出。

以下是结果代码:

代码语言:javascript
复制
type ErrorOr[+T] = Error \/ T
type Result[T] = ReaderWriterStateT[ErrorOr, Environment, List[Output], State, T]

object UserServiceImpl extends UserService {

  def findPlayer(id: Long): Result[Player] = ReaderWriterStateT { (env, state) =>
    val player = Player(1L, "name")
    \/-((List.empty[Output], player, state))
  }

  def updatePlayer(player: Player): Result[Player] = ReaderWriterStateT { (env, state) =>
    \/-((List.empty[Output], player.copy(name = "updated"), state))
  }

}

val userService = UserServiceImpl

val result = (for {
  player <- userService.findPlayer(1L)
  updated <- userService.updatePlayer(player)
} yield updated).run(GameEnvironment, GameState)

result match {
  case \/-((out, player, state)) => println(player)
  case -\/(error) => println(error)
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/45218294

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档