1

我正在使用方案作为我正在学习的课程的一部分。我被告知在作业中使用高阶函数。然而,这个指令似乎有些不清楚。

我不完全理解高阶程序的想法。我可以使用递归来解决所有问题,但这是同一回事。任何人都可以用一个递归函数的例子来解释它,而不是用一个高阶过程编写的例子。

作为第二个问题:

示例:尝试抓取所有奇数

我可以使用(flatten (map odd ((1 4 5) (4 5 1 4 9)))),但是如果有嵌套列表,我可以在嵌套列表上使用 map 吗,例如:

(flatten (map odd ((1 3 (9 5 7)))); 是否有此功能或干净的方法?

4

1 回答 1

2

高阶函数的目的是减少代码中的样板,并减少循环(技术上它是递归,但它的目的是循环,所以我将其称为循环)和实际逻辑之间的耦合。这是一个示例(重新抓取所有奇数):手动循环如下所示:

(define (filter-odd lst)
  (cond ((null? lst) '())
        ((odd? (car lst)) (cons (car lst) (filter-odd (cdr lst))))
        (else (filter-odd (cdr lst)))))

但是请注意,您已经在一个函数中获得了循环和过滤。这使得弄清楚函数在做什么变得更加困难,因为这两个不相关的操作是耦合在一起的。使用更高级别的函数,您可以做不同的事情:

(define (filter pred lst)
  (cond ((null? lst) '())
        ((pred (car lst)) (cons (car lst) (filter pred (cdr lst))))
        (else (filter pred (cdr lst)))))

(define (filter-odd lst)
  (filter odd? lst))

现在注意,如何odd?从循环逻辑中分离出来,现在已经分离成filter? filter现在接受一个函数对象,它决定是否保留该项目,并且调用者filter可以插入他们选择的任何函数。

这就是高阶函数的含义:它是一个以函数对象为参数的函数,用于自定义其操作。

正如您问题的原始编辑中提到的,map是另一个高阶函数,但它不是从列表中过滤项目,而是返回原始列表中每个项目的转换,其中特定转换由map调用者通过范围。


要回答您关于展平等的实际问题,(map filter-odd '((1 3 (9 5 7))))将返回一个包含单个项目的列表,即调用的结果(filter-odd '(1 3 (9 5 7)))。所以不,map不会为您递归到子列表中(也不会filter)。

但是您可以先展平输入(因为无论如何您都在展平输出),然后filter-odd直接调用它。我希望这会给您带来您期望的结果。

(我将你重命名odd为,因为它不太可能与(谓词)filter-odd混淆。)odd?


奖金材料

顺便说一句,两者filtermap都是更通用的高阶函数的特化,称为折叠(或更具体地说,右折叠)。filter折叠可以表达任何一个或都无法容纳的东西map,但它以某种方式涉及遍历列表中的所有项目。这是一个length函数的示例,表示为折叠:

(define (foldl func init lst)
  (if (null? lst) init
      (foldl func (func (car lst) init) (cdr lst))))

(define (length lst)
  (foldl (lambda (elem count)
           (+ count 1))
         0 lst))

这里的好处是该length函数不必担心遍历列表:这是由折叠处理的。它只需要担心每次迭代要做什么(这里只是简单地将 1 加到count0 开始)。

在这种情况下,无论我们从左侧遍历还是从右侧遍历,长度都是相同的,而在 Scheme 中,从左侧遍历更节省空间,因此我们更喜欢这样。但是为了实现mapand filter,右折叠是必要的(否则元素会颠倒 - 尝试在下面的函数中替换foldrwith foldl,你会看到):

(define (foldr func init lst)
  (if (null? lst) init
      (func (car lst) (foldr func init (cdr lst)))))

(define (map func lst)
  (foldr (lambda (elem result)
           (cons (func elem) result))
         '() lst))

(define (filter pred lst)
  (foldr (lambda (elem result)
           (if (pred elem)
               (cons elem result)
               result))
         '() lst))
于 2012-10-07T03:53:08.557 回答