4.4 Functions (Procedures): lambda
lambda 表达式创建一个函数。最简单的情况下,lambda 表达式具有以下形式
(lambda (arg-id ...) body ...+)
带有 n 个 arg-id 的 lambda 形式接受 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 的列表中。
> ((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.
(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 变量有时被称为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 也必须有默认值。
(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] 参数指定了一个带有默认值的基于关键字的参数。
(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.
(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。
(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 函数不能直接支持可选参数或关键字参数。