有什么好的例子:"程序的操作应该将输入值映射到输出值而不是更改数据"

Ani*_*nil 7 functional-programming scala

我在Scala中发现了这句话,解释了它的功能行为.

程序的操作应该将值的输入映射到输出值,而不是在适当的位置改变数据

有人可以用一个很好的例子来解释它吗?

编辑: 请在上下文中解释或举例说明上述句子,请不要让它变得更加混乱

oxb*_*kes 14

这是指最明显的模式,即与Scala相比,编写使用Java集合的代码的方式之间存在差异.如果您正在编写scala但是在Java习惯用法中,那么您将通过适当地改变数据来处理集合.的惯用 Scala代码做同样的将有利于输入值到输出值的映射.

让我们来看看你可能想要对集合做的一些事情:

过滤

在Java中,如果我有一个List<Trade>并且我只对那些用德意志银行执行的交易感兴趣,我可能会这样做:

for (Iterator<Trade> it = trades.iterator(); it.hasNext();) {
    Trade t = it.next();
    if (t.getCounterparty() != DEUTSCHE_BANK) it.remove(); // MUTATION
}
Run Code Online (Sandbox Code Playgroud)

在此循环之后,我的trades集合仅包含相关交易.但是,我已经使用变异实现了这一点- 粗心的程序员可能很容易错过trades是一个输入参数,一个实例变量,或者在方法的其他地方使用.因此,很可能他们的代码现在已被破坏.此外,由于同样的原因,这样的代码对于重构非常脆弱 ; 一个希望重构一段代码的程序员必须非常小心,不要让变异的集合逃避它们打算使用的范围,反之亦然,它们不会意外地使用未变异的集合,它们应该在使用过变异的.

与Scala比较:

val db = trades filter (_.counterparty == DeutscheBank) //MAPPING INPUT TO OUTPUT
Run Code Online (Sandbox Code Playgroud)

创造了一个新的集合!它不会影响任何正在观察trades并且本质上更安全的人.

制图

假设我有一个List<Trade>,我想得到一个Set<Stock>我一直在交易的独特股票.同样,Java中的习语是创建一个集合并对其进行变异.

Set<Stock> stocks = new HashSet<Stock>();
for (Trade t : trades) stocks.add(t.getStock()); //MUTATION
Run Code Online (Sandbox Code Playgroud)

使用scala正确的做法是映射输入集合,然后转换为集合:

val stocks = (trades map (_.stock)).toSet  //MAPPING INPUT TO OUTPUT
Run Code Online (Sandbox Code Playgroud)

或者,如果我们关注性能:

(trades.view map (_.stock)).toSet
(trades.iterator map (_.stock)).toSet
Run Code Online (Sandbox Code Playgroud)

这有什么好处?好:

  1. 我的代码永远不会观察到部分构造的结果
  2. 函数的应用A => BColl[A]获得Coll[B]更清晰.

累积

同样,在Java中,成语必须是变异.假设我们试图将我们所做交易的十进制数量相加:

BigDecimal sum = BigDecimal.ZERO
for (Trade t : trades) {
    sum.add(t.getQuantity()); //MUTATION
}
Run Code Online (Sandbox Code Playgroud)

同样,我们必须非常小心,不要意外地观察到部分构造的结果!在scala中,我们可以在一个表达式中执行此操作:

val sum = (0 /: trades)(_ + _.quantity) //MAPPING INTO TO OUTPUT
Run Code Online (Sandbox Code Playgroud)

或其他各种形式:

(trades.foldLeft(0)(_ + _.quantity)
(trades.iterator map (_.quantity)).sum
(trades.view map (_.quantity)).sum
Run Code Online (Sandbox Code Playgroud)

哦,顺便说一句,Java实现中有一个错误! 你发现了吗?


Sea*_*ons 2

我想说的是:

var counter = 0
def updateCounter(toAdd: Int): Unit = {
  counter += toAdd
}
updateCounter(8)
println(counter)
Run Code Online (Sandbox Code Playgroud)

和:

val originalValue = 0
def addToValue(value: Int, toAdd: Int): Int = value + toAdd
val firstNewResult = addToValue(originalValue, 8)
println(firstNewResult)
Run Code Online (Sandbox Code Playgroud)

这是一个严重的过度简化,但更完整的例子是使用 FoldLeft 来构建结果,而不是自己做艰苦的工作:foldLeft 示例