这不一定是 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 感觉不对。它确实具有清晰且易于使用/编码的优点。此外必须有一个功能性的解决方案吗?

    我想出了另外两个可能的选择:
  • 评估返回一个(可能是新的)StreamListener,但这意味着我必须使 Result 成为 StreamListener 的子类型,这感觉不对。
  • 让评估将 Stream[Int] 作为参数,让 StreamListener 负责消耗尽可能多的 Stream,以确定失败或成功。我看到这种方法的问题是注册监听器的类应该在生成每个数字后查询每个监听器,并在失败或成功时立即采取适当的行动。使用这种方法,我看不出这是如何发生的,因为每个监听器都在强制评估 Stream,直到它完成评估。这里没有单一数字生成的概念。

  • 我在这里忽略了任何标准的 Scala/FP 习语吗?

    最佳答案

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

    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
    

    但是,您不是只是将可变性改组到调用代码以跟踪对结果/流监听器的引用吗?

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

    10-10 02:30