1

我编写了一个简单的程序来查找数字的除数(不包括数字本身)。我已经想出了如何打印它们,但我想让这个函数返回一个包含每个除数的列表。

(define (divisors n)

  (do ((i 1 (+ i 1)))    
    ((> i (floor (/ n 2))))
    (cond 
      ((= (modulo n i) 0)
       (printf "~a " i)))))

我的想法是创建一个本地列表,在我的 printf 表达式所在的位置添加元素,然后让函数返回该列表。我该怎么做呢?我是 Scheme 和 Lisp 的新手。

4

2 回答 2

1

只需创建一个局部变量l并扩展它而不是打印东西。完成后,将其退回。像这样:

(define (divisors n)
  (let ((l '()))
    (do ((i 1 (+ i 1)))    
        ((> i (floor (/ n 2))))
      (cond ((= (modulo n i) 0)
             (set! l (cons i l))))
    l))

请注意,因为每个i都“consed”到 的前面l,所以排序l从高到低。如果(reverse l)需要从低到高排序,则用作返回值。

于 2013-10-19T01:16:27.453 回答
1

你一定要使用必须使用do吗?这是一种方法:

(define (divisors n)
  (do ((i 1 (add1 i))
       (acc '() (if (zero? (modulo n i)) (cons i acc) acc)))
    ((> i (floor (/ n 2)))
     (reverse acc))))

但我相信如果您使用命名let构建输出列表会更容易理解:

(define (divisors n)
  (let loop ((i 1))
    (cond ((> i (floor (/ n 2))) '())
          ((zero? (modulo n i))
           (cons i (loop (add1 i))))
          (else (loop (add1 i))))))

或者如果你碰巧在使用 Racket,你可以for/fold这样使用:

(define (divisors n)
  (reverse
   (for/fold ([acc '()])
     ([i (in-range 1 (add1 (floor (/ n 2))))])
     (if (zero? (modulo n i))
         (cons i acc)
         acc))))

请注意,上述所有解决方案都是以函数式编程风格编写的,这是在 Scheme 中编程的惯用方式 - 不使用变异操作。也可以编写程序风格的解决方案(请参阅@GoZoner 的答案),类似于您使用类 C 语言解决此问题的方式,但这不是惯用的。

于 2013-10-18T22:13:56.543 回答