On this page:
4.4.1 Declaring a Rest Argument
4.4.2 Declaring Optional Arguments
4.4.3 Declaring Keyword Arguments
4.4.4 Arity-Sensitive Functions:   case-lambda

4.4 Functions (Procedures): 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)

arity mismatch;

 the expected number of arguments does not match the given

number

  expected: 2

  given: 1

4.4.1 Declaring a Rest Argument🔗

lambda 表达式还可以具有以下形式

(lambda rest-id
  body ...+)

也就是说,lambda 表达式可以有一个不被括号包围的 rest-id。生成的函数接受任意数量的参数,参数被放入绑定到 rest-id 的列表中。

Examples:
> ((lambda x x)
   1 2 3)

'(1 2 3)

> ((lambda x x))

'()

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

1

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

+The apply Function describes apply.

Examples:
(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 一样多的参数,同时也接受任意数量的额外参数。

Examples:
(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 变量有时被称为rest 参数,因为它接受函数参数的"剩余"部分。带有 rest 参数的函数有时被称为可变参数函数,rest 参数中的元素称为可变参数。

4.4.2 Declaring Optional Arguments🔗

除了仅使用标识符之外,lambda 形式中的参数(rest 参数除外)可以用标识符和默认值来指定:

(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 也必须有默认值。

Examples:
(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 Declaring Keyword Arguments🔗

lambda 形式可以声明通过关键字传递的参数,而不是通过位置传递。关键字参数可以与位置参数混合使用,并且两种参数都可以提供默认值表达式:

+Keyword Arguments introduces function calls with keywords.

(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] 参数指定了一个带有默认值的基于关键字的参数。

Examples:
(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 形式不直接支持创建接受"rest"关键字的函数。要构造接受所有关键字参数的函数,请使用 make-keyword-procedure。提供给 make-keyword-procedure 的函数通过前两个(位置)参数中的并行列表接收关键字参数,然后将应用中的所有位置参数作为剩余的位置参数。

+The apply Function introduces keyword-apply.

Examples:
(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"

+(part ("(lib scribblings/reference/reference.scrbl)" "lambda")) in (part ("(lib scribblings/reference/reference.scrbl)" "top")) provides more on function expressions.

4.4.4 Arity-Sensitive Functions: 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

Examples:
(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 函数不能直接支持可选参数或关键字参数。