Lisp变量不递增?

时间:2013-10-20 10:23:50

标签: lisp scheme

如果在其他地方已经回答了这个问题,我会提前道歉,但我似乎无法找到有关我所遇问题的详细解释。这也是我关于SO的第一篇文章......

基本上这是一项家庭作业,但是,我并不是在寻找解决方案,因为我已经在SO上看到过这方面的工作解决方案。坦率地说,我想实现我自己的解决方案,所以我可以学习,因为我非常有兴趣让我的头脑缠绕lisp / scheme。想法是计算列表中有多少0或任何元素/原子然后显示/返回。

我确信通过查看代码可以很容易地看到我的逻辑正在做什么。我遇到的问题是每次递增时增加totalZeros变量。 (+ 5 myNum)肯定会为myNum增加5。那么为什么不(+ 1 totalZeros)似乎工作?当我单步执行调试器时,我可以看到totalZeros变量永远不会改变。它总是零......

(define (countZeros aList)
  (define totalZeros 0)

  (define (iterator aList)
    (let ((listSize (length aList)))
    (if (> listSize 0)
      (let ((tempVar (car aList)))
      (when (eq? tempVar 0)
        (+ 1 totalZeros))
      (iterator (cdr aList)))
      0)))

   (let ((listSize (length aList)))
   (when (> listSize 0)
     (iterator aList))
   (display totalZeros)))

1 个答案:

答案 0 :(得分:3)

问题是这个表达式:

(+ 1 totalZeros)

totalZeros的值中添加一个,但随后对结果不做任何操作,因此它会丢失。您熟悉其他编程语言吗?上面的内容与C语言类似:

totalZeros + 1;

显然,如果您不在某处存储添加结果,则会丢弃该值。回到你的代码,如果你打算将加法存储在同一个变量中(就像totalZeros++;表达式那样),这就是在Scheme中编写它的方法:

(set! totalZeros (+ 1 totalZeros))

事实上,通过使用上面的代码,您的代码将起作用。虽然可以用类似的程序风格编写正确的程序 - 定义一个局部变量并随意改变它的值,但不建议这样做。这对于类似C语言来说是正确的,但这不是你在Scheme中考虑解决方案的方式,通常你会将修改后的值作为参数传递给函数调用;这是一个等效的,更惯用的解决方案:

(define (countZeros aList)
  (define (iterator aList totalZeros)
    (cond ((null? aList)
           totalZeros)
          ((zero? (car aList))
           (iterator (cdr aList) (add1 totalZeros)))
          (else
           (iterator (cdr aList) totalZeros))))
  (iterator aList 0))

(display (countZeros '(1 2 0 3 0 4 5 0 6 0 7 0 0)))
=> 6

注意null?如何用于确定列表是否为空(而不是使用length),并查看如何使用过程zero?add1。注意totalZeros计数器如何作为参数传递,如何在调用迭代器时将其初始化为0,以及它在结束时如何返回列表为空时递归。还要注意当有几个条件需要考虑时cond如何有用,以及函数应该返回一个值的事实,只有使用display在之后打印该值&# 39; s叫。

以上将解决问题,但它没有使用可用的程序。实际上, 解决问题的首选方法是重用现有功能。在Racket中,您只需调用count过程,告诉它计算列表中找到的所有零:

(define (countZeros aList)
  (count zero? aList))

(display (countZeros '(1 2 0 3 0 4 5 0 6 0 7 0 0)))
=> 6