我正在使用计划作为我正在学习的课程的一部分。我被告知在我的作业中使用高阶函数。然而,这条指令似乎有点不清楚。
我不完全理解高阶程序的想法。我能够使用递归来完成所有问题,但这是同样的事情。任何人都可以通过递归函数与使用高阶函数编写的函数来解释它。
作为第二个问题:
示例:尝试抓住所有奇数
我可以使用(flatten (map odd ((1 4 5) (4 5 1 4 9))))
,但如果有嵌套列表,我可以在嵌套列表上使用map,如:
(flatten (map odd ((1 3 (9 5 7))))
;是否有这种功能或干净的方式来做它?
答案 0 :(得分: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?
(谓词)混淆。)
顺便说一句,filter
和map
都是更通用的高阶函数的特化,称为折叠(或更具体地说,右折叠)。折叠可以表达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}添加到count
,最开始为0)。
在这种情况下,无论我们从左侧还是右侧移动,长度都是相同的,而在Scheme中,从左侧移动更节省空间,因此我们更喜欢这样做。但是为了实现map
和filter
,必须使用右侧折叠(否则元素会反转出来 - 尝试在{x}中使用foldr
替换以下函数,你会看到):
foldl