-2

这是单个整数的代码,如何通过将列表作为参数传递给任意大的输入?

(define (factors n)
  (define (*factors d)
    (cond ((> d n) (list))
          ((= (modulo n d) 0) (cons d (*factors (+ d 1))))
          (else (*factors (+ d 1)))))
  (*factors 1))
            
(display (factors 1111111))
(newline)
4

2 回答 2

0

如果你有一个为一个值做某事的过程,你可以用map它来为一个列表的所有元素做这件事。

(map factors '(50 256 1911))
; ==> ((1 2 5 10 25 50)
;      (1 2 4 8 16 32 64 128 256)
;      (1 3 7 13 21 39 49 91 147 273 637 1911))
于 2021-01-21T23:54:15.947 回答
0

...如何通过将列表作为参数传递给任意大的输入?

已发布过程所描述的*factors过程不是迭代的,即不是尾递归的,它会为大量输入增加堆栈空间。我认为 OP 有兴趣找到该代码的尾递归版本以提高空间效率。

您可以通过将累加器添加到辅助过程来将其转换为迭代过程。这允许将结果存储在累加器中并通过递归调用传递,而不需要在这些调用返回时进行任何进一步的操作,即尾递归。

(define (factors-iter n)
  (define (iter d result)
    (cond ((> d n) (reverse result))
          ((zero? (modulo n d))
           (iter (+ d 1) (cons d result)))
          (else
           (iter (+ d 1) result))))
  (iter 1 '()))

以下是跟踪这些过程的执行的结果:

> (factors-trace 8)
|(%factors 1 8)
| (%factors 2 8)
| |(%factors 3 8)
| |(%factors 4 8)
| | (%factors 5 8)
| | (%factors 6 8)
| | (%factors 7 8)
| | (%factors 8 8)
| | |(%factors 9 8)
| | |()
| | (8)
| |(4 8)
| (2 4 8)
|(1 2 4 8)
(1 2 4 8)

> (factors-iter-trace 8)
|(iter 1 8 ())
|(iter 2 8 (1))
|(iter 3 8 (2 1))
|(iter 4 8 (2 1))
|(iter 5 8 (4 2 1))
|(iter 6 8 (4 2 1))
|(iter 7 8 (4 2 1))
|(iter 8 8 (4 2 1))
|(iter 9 8 (8 4 2 1))
|(1 2 4 8)
(1 2 4 8)

这里factors-tracefactors-iter-tracefactorsfactors-iter定义的略微修改版本,允许跟踪。您可以看到%factors进程的堆栈大小随着计算的进行而增长,但iter堆栈大小保持不变。

正如其他人已经回答的那样,使用factors-iter输入列表的最简单方法是使用map

> (map factors-iter '(4 42 314 2998))
((1 2 4) (1 2 3 6 7 14 21 42) (1 2 157 314) (1 2 1499 2998))
于 2021-01-22T08:59:23.730 回答