标题说明了一切,真的;除了简单地用完元素之外,在保留循环之间的状态和完成迭代的同时迭代集合可能是在命令式编程中完成任何事情的最常见模式。然而,在我看来,这是函数式编程人员同意不谈论的东西,或者至少我从未遇到过它的习语或半标准化的名称,例如 map
, fold
, reduce
, 等等。
我经常在 Scala 中使用以下代码:
implicit class FoldWhile[T](private val items :Iterable[T]) extends AnyVal {
def foldWhile[A](start :A)(until :A=>Boolean)(op :(A, T)=>A) :A = {
if (until(start)) start
else {
var accumulator = start
items.find{ e => accumulator = op(accumulator, e); until(accumulator) }
accumulator
}
}
}
但它很丑。每当我尝试更具声明性的方法时,我都会得到更长且几乎肯定更慢的代码,类似于:
Iterator.iterate((start, items.iterator)){
case (acc, i) if until(acc) => (acc, i)
case (acc, i) if i.hasNext => (op(acc, i.next()), i)
case x => x
}.dropWhile {
case (acc, i) => !until(acc) && i.hasNext
}.next()._1
(更实用的变体将使用
List
s 或 Stream
s,但迭代器的开销可以说比将 items
转换为 Stream
的开销要小,因为后者的默认实现无论如何都在下面使用迭代器)。我的问题是:
1) 这个概念在函数式编程中是否有名称,如果有,与其实现相关的模式是什么?
2) 在 Scala 中实现它的最佳方式是什么(即简洁、通用、懒惰且开销最少)?
最佳答案
这被 Scala 纯粹主义者所反对,但您可以使用 return
像这样的声明:
def foldWhile[A](zero: A)(until:A => Boolean)(op: (A,T) => A): A = items.fold(zero) {
case (a, b) if until(a) => return a
case (a,b) => op(a, b)
}
或者,如果你是那些皱眉头的人,并且想要一个没有肮脏的命令式技巧的纯函数式解决方案,你可以使用一些懒惰的东西,比如迭代器或流:
items
.toStream // or .iterator - it doesn't really matter much in this case
.scanLeft(zero)(op)
.find(until)
关于scala - 函数式编程中是否有 'fold with break' 或 'find with accumulator' 的概念?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36518577/