使用map、append和递归调用解释Racket函数

使用map、append和递归调用解释Racket函数,racket,Racket,此过程接受一个非负整数n,并按真值表所需的特定顺序创建一个包含n0或1的所有列表的列表。我只是想了解这个过程的map部分是如何工作的。在if的第二个参数中,append、map和对所有列表的递归调用是如何协同工作的,对此我特别困惑。任何帮助都将不胜感激 (define all-lists (lambda (n) (if (= n 0) '(()) (append (map (lambda (k) (cons 0 k)) (all-lists (- n 1)))

此过程接受一个非负整数n,并按真值表所需的特定顺序创建一个包含n0或1的所有列表的列表。我只是想了解这个过程的map部分是如何工作的。在if的第二个参数中,append、map和对所有列表的递归调用是如何协同工作的,对此我特别困惑。任何帮助都将不胜感激

(define all-lists
  (lambda (n)
    (if (= n 0)
      '(())
      (append (map (lambda (k) (cons 0 k)) (all-lists (- n 1)))
              (map (lambda (k) (cons 1 k)) (all-lists (- n 1)))
              ))))

理解递归函数的最佳策略是尝试使用比终端函数稍微复杂的情况。那么,让我们用
n=1
试试

在这种情况下,功能变为:

(append (map (lambda (k) (cons 0 k)) (all-lists 0))
        (map (lambda (k) (cons 1 k)) (all-lists 0))
即:

(append (map (lambda (k) (cons 0 k)) '(()))
        (map (lambda (k) (cons 1 k)) '(())))
因此,第一个
map
将函数
(lambda(k)(cons 0 k))
应用于列表
'(())
的所有元素,该列表只有一个元素
'(
),生成
'((0))
(包含由
0
cons
和空列表获得的元素的列表),同样地,第二个映射产生
”((1))
。 这些列表被附加在一起,产生列表
”((0)(1))
,换句话说,长度为1的所有列表的列表,以及
0
1
的所有可能组合

n=2
的情况下,递归情况应用于
'((0)(1))
:因此第一个映射将
0
放在所有元素之前,获得
'((0 0)(0 1))
,而第二个映射生成
'((10)(1))
。如果将这两个列表附加在一起,您将获得
'((0 0)(0 1)(1 0)(1 1))
,这是长度为2的
0
1
的所有可能组合的列表

等等,等等

实际上,该函数的定义并不明确,因为它在每次递归时不必要地计算两次
(所有列表(-n1))
的值,因此它的工作加倍,这已经是指数级的了。因此,通过只计算一次该值,例如通过以下方式,可以提高效率:

(define all-lists
  (lambda (n)
    (if (= n 0)
        '(())
        (let ((a (all-lists (- n 1))))
          (append (map (lambda (k) (cons 0 k)) a)
                  (map (lambda (k) (cons 1 k)) a))))))

将语句与“println”分开有助于理解发生了什么:

(define (all-lists n)
    (if (= n 0)
        '(())
        (let* ((a (all-lists (- n 1)))
               (ol1 (map (λ (k) (cons 0 k)) a))
               (ol2 (map (λ (k) (cons 1 k)) a))
               (ol (append ol1 ol2)))
          (println "---------")
          (println ol1)
          (println ol2)
          (println ol)
          ol)))

(all-lists 3)
输出:

"---------"
'((0))
'((1))
'((0) (1))
"---------"
'((0 0) (0 1))
'((1 0) (1 1))
'((0 0) (0 1) (1 0) (1 1))
"---------"
'((0 0 0) (0 0 1) (0 1 0) (0 1 1))
'((1 0 0) (1 0 1) (1 1 0) (1 1 1))
'((0 0 0) (0 0 1) (0 1 0) (0 1 1) (1 0 0) (1 0 1) (1 1 0) (1 1 1))
'((0 0 0) (0 0 1) (0 1 0) (0 1 1) (1 0 0) (1 0 1) (1 1 0) (1 1 1))
您可以清楚地看到大纲视图(ol1、ol2和组合ol)在每个步骤中是如何变化的