分类:
2008-05-18 11:22:21
Lambda expression are common in functional programming languages. Their syntax varies between languages (and between different forms of lambda calculus), but the basic form of a lambda expressions is:
lambda x1 ... xn.e
A lambda expression defines an unnamed function and consists of:
the parameters of this function: x1 ... xn
.
the expression e which computes the value of the function in terms of the parameters x1 ... xn
.
A simple example of a lambda expression is
lambda x y.x+y
Applying the lambda function means substituting the formal parameters with the actual arguments:
(lambda x y.x+y) 2 3 = 2 + 3 = 5
In the C++ version of lambda expressions the lambda x1 ... xn
part is missing and the formal parameters have predefined names. In the
current version of the library, there are three such predefined formal
parameters, called placeholders: _1
, _2
and _3
.
They refer to the first, second and third argument of the function
defined by the lambda expression. For example, the C++ version of the
definition
lambda x y.x+y
is
_1 + _2
Hence, there is no syntactic keyword for C++ lambda expressions. The
use of a placeholder as an operand implies that the operator invocation
is a lambda expression. However, this is true only for operator
invocations. Lambda expressions containing function calls, control
structures, casts etc. require special syntactic constructs. Most
importantly, function calls need to be wrapped inside a bind
function. As an example, consider the lambda expression:
lambda x y.foo(x,y)
Rather than foo(_1, _2)
, the C++ counterpart for this expression is:
bind(foo, _1, _2)
We refer to this type of C++ lambda expressions as bind expressions.
A lambda expression defines a C++ function object, hence function
application syntax is like calling any other function object, for
instance: (_1 + _2)(i, j)
.
A bind expression is in effect a partial function application. In partial function application, some of the arguments of a function are bound to fixed values. The result is another function, with possibly fewer arguments. When called with the unbound arguments, this new function invokes the original function with the merged argument list of bound and unbound arguments.
A lambda expression defines a function. A C++ lambda expression concretely constructs a function object, a functor, when evaluated. We use the name lambda functor to refer to such a function object. Hence, in the terminology adopted here, the result of evaluating a lambda expression is a lambda functor.
Python支持一种有趣的语法,它允许你快速定义单行的最小函数。这些叫做 lambda 的函数是从Lisp中借用来的,可以被用在任何需要函数的地方。
例 2.21. lambda 函数介绍
>>> def f(x):
... return x*2
...
>>> f(3)
6
>>> g = lambda x: x*2
>>> g(3)
6
>>> (lambda x: x*2)(3)
6
这是一个 lambda 函数,它完成同上面普通函数相同的事情。注意这里的简短的语法;在参数列表周围没有小括号,并且 return 被忽略了(它是默认的,因为整个函数只能是一个表达式)。而且函数没有名字,但是可以将它赋给一个变量进行调用。 |
|
你甚至可以不将 lambda 函数赋值给一个变量而使用它。这不是世上最有用的东西,它只是展示了 lambda 函数只是一个内联函数。 |
总的来说, lambda 函数是一个可以接收任意多个参数(包括)并且返回单个表达式值的函数。 lambda 函数不能包含命令,它们所包含的表达式不能超过一个。不要试图向 lambda 函数中塞入太多的东西;如果你需要更复杂的东西,应该定义一个普通函数,然后想让它多长就多长。
lambda 函数是风格问题。不一定非要使用它们,任何能够使用它们的地方,都可以定义一个分离的普通的函数,用它来替换。我将它们用在需要封装特殊的,非重用的代码上,用许多小的一行函数不会弄乱我的代码。 |
例 2.22. 在 in apihelper.py 中的 lambda 函数
processFunc = collapse and (lambda s: " ".join(s.split())) or (lambda s: s)
顺便这里有几件事情需要注意。首先,我们使用了 技巧的简单形式,没问题,因为一个 lambda 函数总为真。(这并不意味着 lambda 函数不能返回假值。函数本身总是为真,它的返回值可以为任何值。)
第二,我们使用了 split 函数没带参数。你已经看到过它带的使用,但是不带参数它按空白进行分割。
例 2.23. split 不带参数
>>> s = "this is\na\ttest"
>>> print s
this is
a test
>>> print s.split()
['this', 'is', 'a', 'test']
>>> print " ".join(s.split())
'this is a test'
这是一个多行字符串,通过转义字符的定义代替了。 \n 是一个回车; \t 是一个制表符。 | |
split 不带参数按空白进行分割。所以三个空格,一个回车,和一个制表符都是一样的。 |
|
你可以将空白统一化,通过分割一个字符串,然后用单个空格作为分隔符将其重新接起来。这就是 help 函数所做的,将多行文档字符串合并成单行。 |
那么 help 函数到底用这些 lambda 函数, split 函数,和 and-or 技巧做了什么呢?
例 2.24. 将函数赋给一个变量
processFunc = collapse and (lambda s: " ".join(s.split())) or (lambda s: s)
processFunc 现在是一个函数,但它为哪一个函数要看 collapse 变量的值。如果 collapse 为真, processFunc(string) 将压缩空白;否则,processFunc(string) 将返回未改变的参数。
在一个不很建壮的语言实现它,象VB,你将可能创建一个函数,它接收一个字符串和一个 collapse 参数,使用一个 if 语句来判断是否要压缩空白或不压缩,然后返回相应的值。这样效率低,因为函数将不得不处理每种可能性;每次你调用它,它将不得不在给出你所想要的东西之前,判断是否要压缩空白。在Python中,你可以将那种判断逻辑拿到函数外面,而定义一个裁减过的 lambda 函数来给出确切的(并且唯一)你想要的。这样做更有效率,更漂亮,并且更少导致那些令人讨厌的(哦,想到那些参数就头昏)的错误。