在本页中:
4.4.1 声明剩余参数
4.4.2 声明可选参数
4.4.3 声明关键字参数
4.4.4 参数量敏感的函数:case-lambda

4.4 函数(过程):lambda

lambda 表达式用于创建函数。lambda 表达式的最简形式为

(lambda (arg-id ...)
  body ...+)

带有 narg-idlambda 形式接受 n 个参数:

> ((lambda (x) x)
   1)

1

> ((lambda (x y) (+ x y))
   1 2)

3

> ((lambda (x y) (+ x y))
   1)

#<procedure>: arity mismatch;

 the expected number of arguments does not match the given

number

  expected: 2

  given: 1

  arguments...:

   1

4.4.1 声明剩余参数

lambda 表达式可拥有形式

(lambda rest-id
  body ...+)

即,lambda 表达式可拥有单个没有括号括住的 rest-id。 其结果函数接受任意数量的参数,这些参数会作为列表绑定到 rest-id

例如:
> ((lambda x x)
   1 2 3)

'(1 2 3)

> ((lambda x x))

'()

> ((lambda x (car x))
   1 2 3)

1

带有 rest-id 的函数通常使用 apply 来调用另一个接受任意数量参数的函数。

+apply 函数 中描述了 apply

例如:
(define max-mag
  (lambda nums
    (apply max (map magnitude nums))))
> (max 1 -2 0)

1

> (max-mag 1 -2 0)

2

lambda 形式也支持所需参数与 rest-id 结合的形式:

(lambda (arg-id ...+ . rest-id)
  body ...+)

此形式的结果是一个函数,该函数需要的参数量至少与 arg-id 一样多, 此外它还介绍任意数量的附加参数。

例如:
(define max-mag
  (lambda (num . nums)
    (apply max (map magnitude (cons num nums)))))
> (max-mag 1 -2 0)

2

> (max-mag)

max-mag: arity mismatch;

 the expected number of arguments does not match the given

number

  expected: at least 1

  given: 0

变量 rest-id 有时被称作剩余参数,因为它接受函数参数的 “剩余”部分。

4.4.2 声明可选参数

lambda 形式中除剩余参数外的参数不仅可以只有标识符, 还可以有指定了默认值的标识符。

(lambda gen-formals
  body ...+)
 
gen-formals = (arg ...)
  | rest-id
  | (arg ...+ . rest-id)
     
arg = arg-id
  | [arg-id default-expr]

形式 [arg-id default-expr] 的参数是可选的。当在一次应用中该参数并未提供时, default-expr 就会产生默认的值。default-expr 中可引用前面的任何 arg-id,而任何之后的 arg-id 也都必须拥有默认值。

例如:
(define greet
  (lambda (given [surname "Smith"])
    (string-append "Hello, " given " " surname)))
> (greet "John")

"Hello, John Smith"

> (greet "John" "Doe")

"Hello, John Doe"

(define greet
  (lambda (given [surname (if (equal? given "John")
                              "Doe"
                              "Smith")])
    (string-append "Hello, " given " " surname)))

 

> (greet "John")

"Hello, John Doe"

> (greet "Adam")

"Hello, Adam Smith"

4.4.3 声明关键字参数

lambda 形式中可声明按关键字而非位置传入的参数。 关键字参数可与位置固定的参数混合使用,默认值表达式则均支持二者:

+关键字参数 中介绍了带关键字的函数调用。

(lambda gen-formals
  body ...+)
 
gen-formals = (arg ...)
  | rest-id
  | (arg ...+ . rest-id)
     
arg = arg-id
  | [arg-id default-expr]
  | arg-keyword arg-id
  | arg-keyword [arg-id default-expr]

arg-keyword arg-id 指定的参数也被使用同样 arg-keyword 的应用所支持。在参数列表中, 成对的关键字-标识符的位置对于应用中参数的匹配来说无关紧要, 因为它会按照关键字而非位置与参数值像匹配。

(define greet
  (lambda (given #:last surname)
    (string-append "Hello, " given " " surname)))

 

> (greet "John" #:last "Smith")

"Hello, John Smith"

> (greet #:last "Doe" "John")

"Hello, John Doe"

arg-keyword [arg-id default-expr] 参数会根据默认值指定基于关键字的参数。

例如:
(define greet
  (lambda (#:hi [hi "Hello"] given #:last [surname "Smith"])
    (string-append hi ", " given " " surname)))
> (greet "John")

"Hello, John Smith"

> (greet "Karl" #:last "Marx")

"Hello, Karl Marx"

> (greet "John" #:hi "Howdy")

"Howdy, John Smith"

> (greet "Karl" #:last "Marx" #:hi "Guten Tag")

"Guten Tag, Karl Marx"

lambda 形式并不直接支持创建接受“剩余”关键字的函数。 要构造接受所有关键字参数的函数,请使用 make-keyword-procedure。提供给 make-keyword-procedure 的函数通过前两个平行的位置固定参数列表接收关键字参数, 之后该应用中所有位置固定的参数都会作为剩余的位置固定的参数。

+apply 函数 介绍了 keyword-apply

例如:
(define (trace-wrap f)
  (make-keyword-procedure
   (lambda (kws kw-args . rest)
     (printf "Called with ~s ~s ~s\n" kws kw-args rest)
     (keyword-apply f kws kw-args rest))))
> ((trace-wrap greet) "John" #:hi "Howdy")

Called with (#:hi) ("Howdy") ("John")

"Howdy, John Smith"

+The Racket ReferenceProcedure Expressions: lambda and case-lambda一节中提供了关于函数表达式的更多信息。

4.4.4 参数量敏感的函数:case-lambda

case-lambda 形式可创建根据支持的参数量的不同,拥有完全不同行为的函数。 case-lambda 表达式的形式为

(case-lambda
  [formals body ...+]
  ...)
 
formals = (arg-id ...)
  | rest-id
  | (arg-id ...+ . rest-id)

其中每个 [formals body ...+] 都类似于 (lambda formals body ...+)。应用由 case-lambda 产生的函数类似于将 lambda 应用到与给定参数量相匹配的第一个分支。

例如:
(define greet
  (case-lambda
    [(name) (string-append "Hello, " name)]
    [(given surname) (string-append "Hello, " given " " surname)]))
> (greet "John")

"Hello, John"

> (greet "John" "Smith")

"Hello, John Smith"

> (greet)

greet: arity mismatch;

 the expected number of arguments does not match the given

number

  given: 0

case-lambda 函数无法直接支持可选参数或关键字参数。