如何将“while while”算法转换为功能样式?

时间:2014-03-05 15:50:03

标签: algorithm scala functional-programming

在我的命令式Scala代码中,我有一个算法:

def myProcessor(val items: List) {
  var numProcessed = 0
  while(numProcessed < items.size) {
    val processedSoFar = items.size - numProcessed
    numProcessed += processNextBlockOfItems(items, processedSoFar)
  }
}

我想保留“块处理”功能,而不只是在项目列表上执行“takeWhile”。我怎样才能在功能风格中重写它?

2 个答案:

答案 0 :(得分:5)

您需要将其更改为递归样式,其中您在每个循环的“状态”中“通过”

@tailrec
def myProcessor(items: List[A], count: Int = 0): Int = items match{
  case Nil => count
  case x :: xs => 
    processNextBlockOfItems(items, count) 
    myProcessor(xs, count + 1)
}

假设“processedSoFar”不是索引。如果您可以使用列表的当前“头部”:

@tailrec
def myProcessor(items: List[A], count: Int = 0): Int = items match{
  case Nil => count
  case x :: xs => 
    process(x) 
    myProcessor(xs, count + 1)
}

其中process只会处理List的当前“头部”。

答案 1 :(得分:1)

所以,这取决于你认为更实用的东西,但这里是没有'var'的版本

  def myProcessorFunctional(items: List[Int]) {
    def myProcessorHelper(items: List[Int], numProcessed: Int) {
      if (numProcessed < items.size) {
        val processedSoFar = items.size - numProcessed
        myProcessorHelper(items,
            numProcessed + processNextBlockOfItems(items, processedSoFar))
      }
    }
    myProcessorHelper(items, 0)
  }

(为了简单起见,将其列为Ints列表,很容易使其与通用列表一起使用)

我不得不说这是我不介意变量变量的情况之一 - 很明显,没有对它的引用会逃避该方法。

但正如我在上面的评论中所说的那样,processNextBlockOfItems无论如何本质上都是非功能性的,因为它需要它的副作用。一种更实用的方法是它返回到目前为止的处理状态,并且这个状态将在后续调用中更新(并返回)。现在,如果您正在处理两个不同的项目列表,那么您将遇到在processNextBlockOfItems中维护两个不同的部分处理状态的问题......

<强>随后:

仍然忽略状态问题,一个方便的改变是如果processNextBlockOfItems总是处理传递给它的项目列表的第一个块,返回它没有处理的剩余项目(如果使用List,这是方便和有效的,所以很多我想知道你为什么要使用指标。

这会产生类似的结果:

  def myProcessorMoreFunctional(items: List[Int]) {
    if (!items.isEmpty) {
        myProcessorMoreFunctional(processNextBlockOfItems(items))
      }
  }