【发布时间】:2018-07-20 21:40:47
【问题描述】:
我正在解决 Scala 中的Dutch national flag problem,并得出以下代码:
def dutchNationalFlag[T](a: Array[T])(implicit ordering: Ordering[T]) = {
def sort(lo: Int, hi: Int): Unit = {
Stream.iterate((lo, hi, lo + 1)) { acc =>
val (lt, gt, i) = acc
if (ordering.lt(a(i), a(lt))) {
swap(lt, i, a)
(lt + 1, gt, i + 1)
} else if (ordering.gt(a(i), a(gt))) {
swap(gt, i, a)
(lt, gt - 1, i)
} else {
(lt, gt, i + 1)
}
}
.takeWhile(acc => acc._2 >= acc._3)
.lastOption
.foreach { acc =>
val (lt, gt, _) = acc
sort(lo, lt - 1)
sort(gt + 1, hi)
}
}
sort(0, a.length - 1)
}
出于性能原因,我想修改现有数组,而不是创建新数组。上面的代码有效,但它在从iterate 调用swap 时有明显的副作用,这在纯函数式代码中是有问题的。我考虑将swap 替换为稍后在foreach 中执行的方法引用,类似于Haskell IO,但您可以想象,这样做会使代码有些复杂。
其他想法?
【问题讨论】:
-
可变操作在纯函数式编程的上下文中毫无意义。如果您不能进行纯函数式编程并相信编译器会进行优化,那么就没有理由遵守更严格的标准。如果您保存所有交换并在最后应用它们,那仍然会产生您一开始就试图避免的内存开销,而不会获得纯 FP 的任何好处。
-
@Ethan 在我看来,我有一个问题想以有效的方式解决。如果纯 FP 让这变得困难,我没有理由订阅酷儿童俱乐部。也就是说,我不相信纯 FP 代码不能像命令式一样高效。
-
对此有高效、简洁的纯 FP 解决方案。他们不会通过在可变数组上调用交换来做到这一点。并且根据定义这样做的任何解决方案都不能是纯 FP。强制答案生成数组交换意味着您不会得到有效的 FP 答案。
-
@Ethan “高效、简洁的纯 FP 解决方案”正是我想要的。请展示,而不是告诉。
标签: scala functional-programming quicksort side-effects dutch-national-flag-problem