您发布的代码 sn-p 结合了两个可以单独解释的概念(这样可能更有意义):lambda 表达式和高阶函数 .
Lambda 表达式
在 Scheme/Racket 中,函数是普通值,就像数字或列表一样。要创建一个数字,您只需键入它,例如 3 或 25。要创建列表,请使用 list 函数,例如 (list 2 4 6)。要创建函数,请使用 lambda 表单。
通常,当你定义一个函数时,你使用define。例如,这是一个将数字加 1 的函数:
(define (add1 x)
(+ x 1))
但这实际上只是一种简写语法。写出上述定义的完整方式如下所示:
(define add1
(lambda (x)
(+ x 1)))
如您所见,它使用lambda。
如果define 简写更短且更易于阅读,为什么直接使用lambda 会有用?好吧,要理解这一点,您必须考虑高阶函数。
高阶函数
大多数函数采用简单值并产生简单值。例如,上面的add1 函数将一个数字作为参数并生成一个数字作为结果。但是,请记住上面我提到函数也是值。因此,函数实际上可以接受其他函数作为参数,甚至可以生成其他函数作为结果。这些函数称为“高阶函数”。
filter 函数是一个高阶函数。它接受一个函数和一个列表,并使用该函数来选择应将哪些元素保留在结果中。例如,它可用于选择列表中的所有偶数:
> (filter even? (list 1 2 3 4 5))
'(2 4)
注意even? 是一个函数,它作为参数传递给filter。这完全没问题,而且它实际上非常有用! Scheme/Racket 中有许多高阶函数,这些函数是“函数式”编程的重要组成部分。例如,map 函数允许您提供一个函数来应用于列表的每个元素:
> (map add1 (list 1 2 3 4 5))
'(2 3 4 5 6)
当然,这一切都很好,但是如果你想为列表的每个元素添加一个不是 1 的数字怎么办?好吧,您总是可以定义一个添加了正确数量的新函数:
> (define (add25 x)
(+ x 25))
> (map add25 (list 1 2 3 4 5))
'(26 27 28 29 30)
但是,这将是非常愚蠢的。就像您必须使用define 为您的所有号码命名一样,而不是直接将它们输入到程序中。对于只会使用一次的小而简单的函数,没有必要给它们命名。为此,您可以直接使用lambda 表单:
> (map (lambda (x) (+ x 25))
(list 1 2 3 4 5))
'(26 27 28 29 30)
这就是您问题的 sn-p 中发生的情况。您可以为内部 lambda 命名,如下所示:
(define (not-an-apple? item)
(not (symbol=? item 'apple)))
(define (eat-apples lst)
(filter not-an-apple? lst))
但是,在这种情况下,只编写内联函数会更容易,因为单独的 not-an-apple? 函数可能不是非常有用。