如今函数式编程越来越流行。越来越多的编程语言支持函数式编程风格,人们学习如何使用它们。函数式编程已不像以前那么小众——现在Ruby,Java和JavaScript都使用了函数式编程思想。

functional-programming

这些语言都有函数式的特性,但不是函数式语言。我的经验之谈,函数式语言,如Erlang或ML拥有其他主流语言缺少的特性,能让编程更加安全的特性。其中之一便是使用递归和参数模式匹配(argument pattern matching)控制循环。你也可以将这些设计用于流控制( flow control)。另一个便是认真对待常量赋值。我这里提到常量赋值因为在这些语言中,一旦你给变量绑定一个值,直到离开作用域前会一直绑定。这个特性带来的弊端就是学习如何使用它们开发软件很困难。对于我们这些用强类型语言的开发者,尤其困难。

递归和模式匹配

函数式编程语言特性是运行期优化递归。使用尾调用优化,运行期提供高效的回调环境,使每个回调用相同的栈帧(stack frame)。再加上参数模式匹配,你可以像写归纳法证明(高中数学的归纳法)那样写表达式函数。你有一个基础步骤和归纳步骤。基础步骤结束递归,归纳步骤重复递归。通过这种方式,你可以定义函数处理列表或集合。函数的每个变量在每次调用中绑定,这使得变量绑定更易于管理。下面是个伪代码例子:

looper(_) := return 0
looper(h, t) := return t + looper(h)

这里,我们定义了一个函数looper()对列表内容求和。

第一个步骤是基础步骤——如果列表为空,我们返回0。第二个步骤是归纳步骤——如果列表有头元素和尾元素,然后我们把尾元素通过递归调用looper()方法求和。如果列表中只剩一个元素,这个元素绑定到变量t,递归调用匹配基础步骤(因为变量h为空),然后递归展开。

在函数式语言中,尾调用优化确保了栈帧重复使用,所以本质上结构和for、while循环一样,比如C语言。

如果你在Ruby或JavaScript中使用它,你必须确保在使用函数循环列表前尾递归优化是可用的。如果没有,你将在递归中遇到性能问题。你在Ruby或JavaScript中只需要把基础步骤放在归纳步骤前面就行。

常量赋值

这点在函数式语言中很难实现。毕竟用不可变的值表示可变的状态非常困难。你又该怎么办呢?

记住,变量赋值只在当前作用域有效。所以你如何应对这种情况?你让作用域很小,只在函数调用时绑定必须的变量。你不能编写修改状态的代码,比如在一系列循环中。你只能在函数调用时绑定状态,然后递归。通过这种方式,你可以维护状态改变,在绑定状态变量值时很难出现错误。

不要使用全局变量。它会跑到作用域外。

相比那些所谓拥有函数式编程的语言,这就是你将在真正函数式语言中看到的两点关键不同点。函数式程序设计让你的重用能力更上一层楼,使代码更清晰,不过在没有优化的运行环境中会有潜在的性能代价。

你可能感兴趣的内容
函数式思维和函数式编程 收藏,2066 浏览
使用C#进行函数式编程 收藏,2369 浏览
0条评论
VI

Vivek

这家伙太懒了,什么都没留下
Owner