微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

改进方案中的迭代函数

如何解决改进方案中的迭代函数

我经常在scheme中编写迭代函数:它使编写递归过程变得更加简单。以下是尝试使用迭代过程对列表中的项目进行平方的示例:

(define square (lambda (x) (* x x)))
(define (square-list items)
  (define result nil) ; set result
  (define (iter items-remaining)
    (if (null? items-remaining)
        result
        (set! result (cons (car items-remaining) (iter (cdr items-remaining))))))
  (iter items))

(square-list '(1 2 3 4 5))
; (4 9 16 25)

我的主要问题是:

  • 有没有办法在内部过程之前先定义result?我试图使迭代过程具有 define (iter items-remaining answer)函数原型,但很难以这种方式实现它。

  • 如果没有,那为什么不可能?

解决方法

发布的代码不起作用;但即使经过修复使其确实工作,这也不是惯用的 Scheme 解决方案。

要使发布的代码工作:

  • nil 必须替换为 '(),因为 Scheme 不代表带有 nil
  • 的空列表
  • square 必须在 caritems-remaining 上调用
  • set! 应该通过添加平方数来修改 result,而不是尝试添加递归调用的结果。这在这里根本不起作用,因为 set! 返回未指定的值;但即使它确实有效,这也不是尾递归的(即,这不是一个迭代过程)
  • result 的值必须返回,而且必须先反转,因为 result 确实是一个累加器

这是一个固定版本:

(define (square-list-0 items)
  (define result '()) ; set result
  (define (iter items-remaining)
    (cond ((null? items-remaining)
           result)
          (else
           (set! result (cons (square (car items-remaining))
                              result))
           (iter (cdr items-remaining)))))
  (iter items)
  (reverse result))

更好的解决方案不会使用变异,也不需要(define result '())

(define (square-list-1 xs)
  (define (iter xs acc)
    (if (null? xs)
        (reverse acc)
        (iter (cdr xs) (cons (square (car xs)) acc))))
  (iter xs '()))

此处将累加器 acc 添加到 iter 过程的 lambda 列表中。在计算结果时,它们被分配到 acc,这意味着在此过程结束时,acc 中的第一个数字基于 xs 中的最后一个数字。因此,累加器在返回之前被反转。

执行此操作的另一种方法,可能也是更惯用的解决方案,是使用 命名为 let

(define (square-list-2 xs)
  (let iter ((xs xs)
             (acc '()))
    (if (null? xs)
        (reverse acc)
        (iter (cdr xs) (cons (square (car xs)) acc)))))

这更简洁一点,它允许您在 iter 过程定义的开始处将参数绑定到它们的参数。

以上三个解决方案都定义了迭代过程,并且三个都给出了相同的结果:

> (square-list-0 '(1 2 3 4 5))
(1 4 9 16 25)
> (square-list-1 '(1 2 3 4 5))
(1 4 9 16 25)
> (square-list-2 '(1 2 3 4 5))
(1 4 9 16 25)

当然,您可以只使用 map

> (map square '(1 2 3 4 5))
(1 4 9 16 25)

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。