Recursion 方案:高阶过程和递归

Recursion 方案:高阶过程和递归,recursion,map,scheme,Recursion,Map,Scheme,我正在使用scheme作为我正在学习的课程的一部分。我被告知在作业中使用高阶函数。然而,这个说明似乎有点不清楚 我不完全理解高阶程序的概念。我可以用递归来回答所有的问题,但这是一样的。有人能用递归函数和用高阶过程编写的函数的例子来解释它吗 作为第二个问题: 示例:尝试获取所有奇数 我可以使用(展平(映射奇数((1 4 5)(4 5 1 4 9))),但是如果有嵌套列表,我可以在嵌套列表上使用映射吗 (展平(映射奇数((13(9 5 7)));有没有一个函数可以实现这一点还是一个干净的方法?高阶函

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

我不完全理解高阶程序的概念。我可以用递归来回答所有的问题,但这是一样的。有人能用递归函数和用高阶过程编写的函数的例子来解释它吗

作为第二个问题:

示例:尝试获取所有奇数

我可以使用
(展平(映射奇数((1 4 5)(4 5 1 4 9)))
,但是如果有嵌套列表,我可以在嵌套列表上使用映射吗


(展平(映射奇数((13(9 5 7)))
;有没有一个函数可以实现这一点还是一个干净的方法?

高阶函数的目的是减少代码中的样板文件,减少循环之间的耦合(从技术上讲,这是一个递归,但它的目的是循环,所以我将这样引用它)以及实际逻辑。下面是一个示例(重新获取所有奇数):手动循环如下所示:

(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'((13(95 7)))
将返回一个包含单个项的列表,这是调用
(filter odd'(13(95 7)))
的结果。因此,不,
map
不会为您递归到子列表中(而且
filter

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

(我将您的
odd
重命名为
filter odd
,因为这不太可能与
odd?
(谓词)混淆。)


奖金材料 顺便说一下,
filter
map
都是一个更一般的高阶函数的特化,称为折叠(或者更具体地说,是右折叠).fold可以表示
filter
map
都无法容纳的内容,但却涉及遍历列表中的所有项目。下面是
length
函数的一个示例,表示为fold:

(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
,需要右折叠(否则,元素会出现相反的结果---尝试在下面的函数中用
foldl
替换
foldr
,您将看到):


非常感谢你,我得到了大部分,我会再通读一遍,以确保:)真的很有帮助。
(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))