scala - 从可变算法中发现功能算法

标签 scala functional-programming algorithm

这不一定是 Scala 问题,而是与避免可变状态、函数式思维等相关的设计问题。碰巧我正在使用 Scala。

鉴于这组要求:

  • 输入来自本质上无限的 1 到 10 之间的随机数流

  • 最终输出是 SUCCEED 或 FAIL

  • 在任何特定时间都可以有多个对象“监听”流,并且它们可以在不同时间开始监听,因此它们都可能对“第一个”数字有不同的概念;因此,流的监听器需要与流本身分离。

伪代码:

if (first number == 1) SUCCEED
else if (first number >= 9) FAIL
else {
  first = first number
  rest  = rest of stream
  for each (n in rest) {
    if (n == 1) FAIL
    else if (n == first) SUCCEED
    else continue
  }
}

这是一个可能的可变实现:

sealed trait Result
case object Fail extends Result
case object Succeed extends Result
case object NoResult extends Result

class StreamListener {
  private var target: Option[Int] = None

  def evaluate(n: Int): Result = target match {
    case None =>
      if (n == 1) Succeed
      else if (n >= 9) Fail
      else {
        target = Some(n)
        NoResult
      }

    case Some(t) =>
      if (n == t) Succeed
      else if (n == 1) Fail
      else NoResult
  }
}

这会起作用,但我闻起来有味道。 StreamListener.evaluate 不是引用透明的。而且使用 NoResult token 感觉不对。它确实具有清晰且易于使用/编码的优势。除此之外必须有一个功能性的解决方案吗?

我想出了另外两种可能的选择:

  • 让 evaluate 返回一个(可能是新的)StreamListener,但这意味着我必须将 Result 设为 StreamListener 的子类型,这感觉不对。

  • 让 evaluate 将 Stream[Int] 作为参数,并让 StreamListener 负责使用确定失败或成功所需的尽可能多的 Stream。我看到这种方法的问题是,注册监听器的类应该在生成每个数字后查询每个监听器,并在失败或成功时立即采取适当的操作。使用这种方法,我看不出这是怎么发生的,因为每个监听器都在强制对 Stream 进行评估,直到它完成评估。这里没有单数生成的概念。

我在这里忽略了任何标准的 Scala/FP 习惯用法吗?

最佳答案

考虑到您的第一个可能选项,我不确定您为什么要将 Result 设为 StreamListener 的子类型,而不是仅将与 StreamListeners 相关的特定 Result 子类型设为 StreamListeners。

sealed trait Result
sealed trait FinalizedResult extends Result

trait StreamListener {
  def evaluate(n: Int): Result
}

case object Uninitialized extends Result with StreamListener {
  def evaluate(n: Int): Result = {
    n match {
      case i if (n == 1) => Succeed
      case i if (n >= 9) => Fail
      case _ => Initialized(n)
    }
  }
}

case class Initialized(target: Int) extends Result with StreamListener {
  def evaluate(n: Int): Result = {
    n match {
      case i if (n == target) => Succeed
      case i if (n == 1) => Fail
      case _ => this
    }
  } 
}

case object Succeed extends FinalizedResult
case object Fail extends FinalizedResult

但是,您不只是将可变性改组到调用代码以跟踪对 Results/StreamListeners 的引用吗?

关于scala - 从可变算法中发现功能算法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2806496/

相关文章:

具有不接受输入参数类型的通用参数类型的 Swift 高阶函数(Church pair aka cons)

algorithm - 在有向图中检测循环的最佳算法

scala - Spark中随机初始化的数据框

scala - 修改 Scala 中 (String, String) 变量的位置

scala - Scala其他实例的 protected 成员

scala - 为什么在 val 变量上使用 += 和 a=x+y 时会出现不同的错误消息?

function - F#:像函数一样应用值

haskell - 在 Haskell 中维护复杂状态

algorithm - 使用常量存储总结无限序列

c++ - 在 C++ 中,检查一个数字是否已经添加到列表中,而不用暴力搜索该列表