这不一定是 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/