SICP Ex2.41:地图和平面图

问题描述

在SICP练习2.41中,作者要求您设计一个过程,该过程将列出三个小于某个特定数字的不同数字,并“过滤”总和等于另一个任意数字的三元组。

这是我的程序:

(define (unique-pair-sum n s)
  (define (unique-triplet a) 
        (flatmap (lambda (i)
           (flatmap (lambda (j)
              (map (lambda (k) (list i j k))
                 (enumerate-interval 1 (- j 1))))
              (enumerate-interval 1 (- i 1))))
           (enumerate-interval 1 a)))
  (filter (lambda (x) (= (+ (car x) (cadr x) (caddr x)) s)) 
          (unique-triplet n)))

这是本书中所述的flatmap过程:

(define (flatmap proc seq) (accumulate append nil (map proc seq)))

和示例结果:

(unique-pair-sum 6 9) ; ((4 3 2) (5 3 1) (6 2 1))

如您所见,此代码没有任何问题,但是当我将flatmap之前的“ (lambda (j)...)”更改为简单的“ map”时,会发生一些奇怪的事情:

(unique-triplet 6) ; (() () ((3 2 1)) () ((4 2 1)) ((4 3 1) (4 3 2)) () ((5 2 1)) ((5 3 1) (5 3 2)) ((5 4 1) (5 4 2) (5 4 3)) () ((6 2 1)) ((6 3 1) (6 3 2)) ((6 4 1) (6 4 2) (6 4 3)) ((6 5 1) (6 5 2) (6 5 3) (6 5 4)))

但是原始代码可以正常工作:

(unique-triplet 6) ; ((3 2 1) (4 2 1) (4 3 1) (4 3 2) (5 2 1) (5 3 1) (5 3 2) (5 4 1) (5 4 2) (5 4 3) (6 2 1) (6 3 1) (6 3 2) (6 4 1) (6 4 2) (6 4 3) (6 5 1) (6 5 2) (6 5 3) (6 5 4))

我知道这不是一个真正的“问题”,因为我已经设法解决了(在一些外部帮助下)。我很好奇这种差异背后的原因。

解决方法

map将列表中的每个元素替换为一个新元素:

   1        2        3        4               ...
  10       20       30       40               ...

flatmap将列表中的每个元素替换为一些新元素:

   1        2        3        4               ...
  10 11    20                40 41 42 43      ...

如您所见,如果某个元素被flatmap替换为完全没有元素,则与从输入列表中过滤掉一样。

如果仅用flatmap代替map,则列表中的每个元素都将被替换为 list 的一些新元素:

   1        2        3        4               ...
 (10 11)  (20)      ()      (40 41 42 43)     ...

(edit :)并不是您想要的,因为您希望空列表消失以达到过滤效果。

因此,您应该在扩展和扩展新值的最后一步有条件地生成它们,从而实现过滤 ,为

(define (unique-triplets-sum n s)
  (define (unique-triplets-summing-up-to s a) 
     (flatmap (lambda (i)
        (flatmap (lambda (j)
            (flatmap (lambda (k)              ;; NB: flatmap
                       (if (= (+ i j k) s)
                         (list (list i j k))  ;; NB: (list _triplet_)
                         '()))                ;;     OR _empty_list_
                (enumerate-interval 1 (- j 1))))
             (enumerate-interval 1 (- i 1))))
          (enumerate-interval 1 a)))
  (unique-triplets-summing-up-to s n))

>  (unique-triplets-sum 5 8)
'((4 3 1) (5 2 1))

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...