为什么这个方案计划不能按预期工作?

时间:2013-01-09 02:43:09

标签: scheme r5rs

(define wadd (lambda (i L)
                (if (null? L) 0
                    (+ i (car L)))
                    (set! i (+ i (car L)))
                          (set! L (cdr L))))

(wadd 9 '(1 2 3))

这不会返回任何内容。我希望它可以(3 + (2 + (9 + 1)),它应该等同于15。我是否以错误的方式使用set!?我是否可以在set!条件下致电if

2 个答案:

答案 0 :(得分:3)

我从你的代码中推断出你打算以某种方式遍历列表,但wadd过程中没有任何内容迭代列表 - 没有递归调用,没有循环指令,没有:只是一个误用的条件和一个一对set!只能执行一次。我不会尝试修复问题中的程序,无法修复 - 我宁愿向您展示解决问题的正确方法。你想要这些方面的东西:

(define wadd
  (lambda (i L)
    (let loop ((L L)
               (acc i))
      (if (null? L)
          acc
          (loop (cdr L) (+ (car L) acc))))))

执行时,上一个过程将评估此表达式:(wadd 9 '(1 2 3)),如下所示: (+ 3 (+ 2 (+ 1 9)))。请注意,正如@Maxwell指出的那样,使用foldl可以更简洁地表达上述操作:

(define wadd
  (lambda (i L)
    (foldl + i L)))

作为一般规则,在Scheme中,你不会像在命令式C语言中那样频繁地使用赋值(set!指令) - 首选函数式编程风格,它依赖于关于不会改变状态的递归和操作。

答案 1 :(得分:2)

我认为如果你修复了缩进,你的问题就会变得更加明显。

函数set!返回<#void>(或类似虚无的东西)。你的lambda wadd做了以下事情:

  1. 检查L是否为空,评估为0或i + (car L),然后丢弃结果。
  2. 修改i并评估为
  3. 修改L并且不返回任何内容
  4. 如果在lambda中放置多个语句,它们将明确地包含在begin语句中:

    (lambda () 1 2 3) => (lambda () (begin 1 2 3))
    

    在序列中多个表达式的begin语句中,整个begin求值为最后一个语句的结果:

    (begin 1 2 3) => 3