1

我只是在学习 Scala 的同时开始了我的 FP 之旅。

现在需要List[String]在未过滤的 Web 应用程序中维护一个。当POST请求发送到端点时,应该从文件更新列表。当 GET 请求发送到同一端点时,将使用该列表。

现在,我试图避免使用var来保存列表。我知道有时我们必须使用 var 但只是好奇是否有一种优雅的方式来处理这种情况。我试过使用 scalaz.State Iterator 和 Steam。但是因为我不知道如何将当前的不可变状态传递给下一个请求而被卡住了。请问有什么建议吗?

def update = State( l => {
  retrieve(filepath) match {
    case Success(lines) => (lines.split("[,\n\r]").toVector.map (_.trim), true)
    case Failure(_) => {
      log.error(s"Cannot retrieve the file.")
      (l, false)
    }
  }
})

def isContained(message: String) = State(l => (l, l.exists(message.contains)))

/* assume the following get or post method will be invoked when GET or POST request is sent to the endpoint */

def post() = update(Vector.empty) // how can I pass the updated state to the get method

def get(msg: String): Boolean = isContained(msg)(???)._2

然后我不知道如何将当前状态作为输入传递给下一次访问而不使用var.

4

1 回答 1

1

天下没有免费的午餐。如果您想避免可变性并避免将状态存储在某处,则需要使用返回值。

State只不过是一个函数A => B(我出于某种目的对其进行了一些简化),其中A是初始状态,B是最终结果

所以在你的情况下,模型看起来像:

def post(newMessage: String, state: List[String]): List[String] = {
  newMessage :: state
}

def get(msg: String, state: List[String]): Boolean = {
  state.contains(msg)
}

正如您在此处看到的,您需要为每个postand提供当前状态get。帖子只会从文件中添加一条新消息(将您的业务逻辑放在这里),并返回一个新状态。对于get,您需要提供当前状态,以便能够检索您想要的东西。你可以这样重写它:

def post(newMessage: String): List[String] ⇒ List[String] = state ⇒ {
  newMessage :: state
}

def get(msg: String): List[String] ⇒ Boolean = 
  _.contains(msg)

请注意,post 会准确地返回您A ⇒ A(where A = List[String])。

ScalaZState为您提供 Monad 用于链接内部函数以进行理解以及一些额外的便利(如map,getsput)。但本质上 - 基础模型是相同的。

这段代码更准确地表示了什么State

  type YourListState = List[String] ⇒ List[String]

  def post(newMessage: String, state: YourListState): YourListState = li ⇒ {
    newMessage :: state(li)
  }

  def get(msg: String, state: YourListState): List[String] ⇒ Boolean = {
    state(_).contains(msg)
  }

这使您可以组合状态并提供初始值并在需要时“运行”它,不确定您是否真的需要它。

于 2016-08-31T18:23:26.153 回答