2

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

基本上这是一个家庭作业,但是,我不是在寻找解决方案,因为我已经在 SO 上看到了一个可行的解决方案。坦率地说,我想实现自己的解决方案,这样我就可以学习,因为我非常有兴趣让我的头脑围绕 lisp / 方案。这个想法是计算列表中有多少个 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)))
4

1 回答 1

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

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

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

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

(display (countZeros '(1 2 0 3 0 4 5 0 6 0 7 0 0)))
=> 6
于 2013-10-20T14:31:50.570 回答