函数式编程有什么不同?
函数式编程原则上是声明性的。您说的是结果而不是如何计算结果。
让我们看一下代码片段的实际功能实现。在Haskell中,它将是:
predsum pred numbers = sum (filter pred numbers)
是否清楚什么结果?相当是满足谓词的数字之和。如何计算?我不在乎,请问编译器。
您可能会说使用sum
和filter
是一个把戏,它并不重要。然后在没有这些帮助者的情况下实施它(尽管最好的方法是首先实施它们)。
sum
递归不使用“功能编程101”解决方案:
sum pred list =
case list of
[] -> 0
h:t -> if pred h then h + sum pred t
else sum pred t
仍然很清楚单函数调用的结果是什么。是0
或recursive call + h or 0
取决于pred h
。即使最终结果不是立即显而易见的,它仍然很简单(尽管稍加练习,这实际上就像for
循环一样)。
将其与您的版本进行比较:
public int Sum(Func<int,bool> predicate, IEnumerable<int> numbers){
int result = 0;
foreach(var item in numbers)
if (predicate(item)) result += item;
return result;
}
结果是什么?哦,我明白了:单一return
声明,在这里没有惊喜return result
。
但是什么result
呢?int result = 0
?似乎不正确。您稍后再做些事情0
。好的,您添加item
。等等。
当然,对于大多数程序员来说,这很明显是在像这样的简单函数中发生的,但是要添加一些额外的return
语句,这样一来,突然变得很难跟踪。所有的代码是关于如何和什么留给读者找出- 这显然是一个非常迫切的风格。
那么,变量和循环是否错误?
没有。
他们解释了很多事情,并且要求可变状态要快的许多算法。但是变量本质上是必须的,它解释了如何而不是什么,并且几乎没有预测它们的值,可能是在几行之后或在几次循环迭代之后。循环通常需要状态才有意义,因此它们本质上也是必不可少的。
变量和循环根本不是函数编程。
摘要
当代的泛函式编程比范式更具风格和思维方式。在这种心态中,强烈偏爱纯函数,但这实际上只是一小部分。
最广泛使用的语言允许您使用某些功能构造。例如,在Python中,您可以选择以下选项:
result = 0
for num in numbers:
if pred(result):
result += num
return result
要么
return sum(filter(pred, numbers))
要么
return sum(n for n in numbers if pred(n))
这些函数表达式非常适合此类问题,并且可以使代码更短(并且更短是好的)。您不应该无所顾忌地用它们替换命令性代码,但是当它们适合时,它们几乎总是一个更好的选择。
item
变量在循环中发生突变时,它具有副作用。