Lisp变量不递增?

Lisp变量不递增?,lisp,scheme,Lisp,Scheme,如果其他地方已经回答了这个问题,我提前表示歉意,但是我似乎找不到对我所遇到问题的详细解释。这也是我的第一篇文章,所以 基本上这是一个家庭作业,然而,我不是在寻找一个解决方案,因为我已经看到了一个这样的工作解决方案。坦白地说,我想实现我自己的解决方案,这样我就可以学习了,因为我对lisp/scheme非常感兴趣。其思想是计算列表中有多少个0或任何元素/原子,然后显示/返回 我确信通过查看代码,很容易看到我的逻辑在做什么。我遇到的问题是每次递归时增加totalZeros变量。(+5 myNum)肯定

如果其他地方已经回答了这个问题,我提前表示歉意,但是我似乎找不到对我所遇到问题的详细解释。这也是我的第一篇文章,所以

基本上这是一个家庭作业,然而,我不是在寻找一个解决方案,因为我已经看到了一个这样的工作解决方案。坦白地说,我想实现我自己的解决方案,这样我就可以学习了,因为我对lisp/scheme非常感兴趣。其思想是计算列表中有多少个0或任何元素/原子,然后显示/返回

我确信通过查看代码,很容易看到我的逻辑在做什么。我遇到的问题是每次递归时增加totalZeros变量。(+5 myNum)肯定会在任何myNum的基础上增加5。因此,为什么(+1 totalzero)似乎不起作用?当我逐步通过调试器时,我可以看到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 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/COD>是有用的,并且函数应该返回一个值,只有使用<代码>显示< /代码>才能在调用它之后打印该值。 上述方法可以解决问题,但没有利用现有的程序。事实上,解决问题的首选方法是重用现有功能。在Racket中,您只需调用
count
过程,告诉它计算列表中找到的所有零:

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

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

(+1个全零)
1
添加到
totalZeros
中,但放弃结果。这就像说
totalZeros+1而不指定它。您可以使用
(setq totalZeros(+totalZeros 1))
(incf totalZeros)
。您已经实现了一个递归解决方案(这是需要执行的函数),但递归函数没有返回任何内容。您应该从递归函数返回计数,而不是试图修改共享状态(这不是函数式操作)。@mbrach这似乎是scheme,
set而不是
setq
incf
是的,我确实在使用Scheme,我应该更具体一些。。。非常感谢大家的评论。我的背景是C风格的语言。这绝对是一个大脑放屁。现在可以正常工作了。是的,你可以肯定地告诉我的代码有一个C风格的逻辑,因为背景是基于C的语言。我不知道为什么我认为(+1 totalzero)实际上是在用1存储和更新当前值。就像你说的,开始!工作完美,因为我使用的方案。总的来说,你的例子让我觉得很多东西都很有意思。我非常感谢你花时间发布你所做的事情。有一件事我不确定,使用if语句总是必须有一个else部分正确吗?所以为什么我用的时候。。。cond后面只需要一个语句?为什么不使用when而不是cond?@user2899772在Racket
if
中必须有一个
else
部分,如果您只需要一个条件,则必须使用
when
。另一方面,
cond
类似于一系列
if-else-if-else
语句,并具有隐式
begin
的额外好处,这意味着可以在每个条件下放置多个表达式。当
时,
也是如此:您可以在其中放置多个表达式,而如果
时,
将每个分支中的表达式限制为一个。