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

时间:2016-10-13 03:22:19

标签: racket

此过程采用非负整数n,并按照真值表所需的特定顺序创建所有n 0或1的列表的列表。我只是想了解程序的地图部分是如何工作的。我特别感到困惑的是,如果追加,映射和对所有列表的递归调用如何在if的第二个参数中一起工作。任何帮助将非常感谢!

(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)))
              ))))

2 个答案:

答案 0 :(得分: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)) (包含由cons 0和空列表获得的元素的列表),并且第二个映射生成'((1))的方式相同。 这些列表会附加在一起,生成列表'((0) (1)),换句话说,列出所有长度为1的列表,其中包含01的所有可能组合。

对于n=2,递归案例适用于'((0) (1)):因此第一张地图会在所有元素之前放置0,获取'((0 0) (0 1)),而第二张地图生成'((1 0) (1 1))。如果您将这两个列表附加在一起,则会获得'((0 0) (0 1) (1 0) (1 1)),这是01的长度为2的所有可能组合的列表。

依此类推,等等......

实际上,函数没有很好地定义,因为它在每次递归时不必要地计算(all-lists (- n 1))的值两次,因此它的工作加倍,这已经是指数。因此,通过仅计算一次该值,可以提高效率,例如以下列方式:

(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))))))

答案 1 :(得分:0)

将陈述与' 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)是如何变化的。