函数式编程






3.76/5 (9投票s)
函数式编程的优势
引言
软件工程的第一步是掌握编程语言,这引导我们根据特定场景选择合适的语言。 主要有两种范式:命令式和声明式。 命令式语言使用一系列语句来完成目的。
什么是函数式编程?
它们具有显式的初始化和值分配,而声明式语言仅使用表达式,没有任何详细的控制流。 函数式编程是声明式编程的一个子集,而面向对象编程是命令式语言的一个子集。 C# 和 Java 是面向对象编程语言,而 F# 和 Scala 是函数式编程语言。 虽然可以在函数式语言中使用面向对象编程的概念,例如类、接口和继承,反之亦然,例如在 C# 中使用 lambda 表达式,这是一种函数式语言的概念。
//Imperative
string[] stringList = new string[] { "Mahsa", "Kashi", "Hassankashi" };
List oopList = new List();
foreach (string str in stringList)
{
if (str.Length == 5)
{
oopList.Add(str);
}
}
//Declarative - Functional
List functionalList = stringList.Where(s => s.Length == 5 ).ToList();
为什么选择函数式编程?
函数式编程成为技术前沿的最重要原因是,在处理多个处理器时,它具有高效且可靠的行为,换句话说,它在并行编程方面具有最佳性能。
通过尾调用优化避免堆栈溢出
另一个原因是,函数式语言中的循环和迭代将通过带有 TCO(尾调用优化)的递归来完成。 TCO 是一种在不使用单独的堆栈帧的情况下调用函数的方法,从而避免堆栈溢出。 例如,在下面的代码中,Factorial(4)
的计算需要 4 个单独的堆栈帧,而函数式语言中的下一个计算只需要一个堆栈帧。
这不是 TCO
def factorial(n):
if n == 0:
return 1
return n * factorial(n-1)
这是 TCO
def factorial(n):
return fact(n, 1)
def fact(n, number):
if n == 0:
return number
return fact(n-1, number*n)
借助不可变对象,作为线程安全的手段,避免竞争条件和死锁。
什么是竞争条件?
在多线程概念中,当两个或多个线程同时尝试获取共享资源或对象时。
什么是死锁?
在多线程概念中,当进程 1 持有并锁定资源 2 并等待资源 1 时,而此时进程 2 持有并锁定资源 1 并等待资源 2 时。
什么是线程安全?
在多线程概念中,线程安全确保每个线程可以在同时进行时正确执行,而不会产生意外的交互。
什么是不可变?
不可变对象的 state 或值在创建后无法更改。 a
是可变的,因为它的值会被更改
a = 1
b = 2
a = a + b
在创建时,a
应该定义为只读和不可变,以防止更改其值。
结论
由于不可变在函数式编程中是线程安全的,因此它对于无限循环或 foreach
循环(尤其是在数学函数中)非常有用,并可以防止竞争条件和死锁。