2

I apologize in advanced if this has been answered elsewhere, however I can't seem to find a detailed explanation for the issue I am having. This is also my first post on SO...

Basically this is a homework assignment, however, I am not looking for a solution as I have already seen a working solution for this on SO. Frankly I want to implement my own solution so I can learn as I am very interested in getting my head wrapped around lisp / scheme. The idea is to count how many 0's or whatever element / atom are within a list then display / return.

I am sure by looking at the code it will be easy to see what my logic is doing. The issue I am having is incrementing the totalZeros variable each time I recurse. (+ 5 myNum) would certainly add 5 to whatever myNum is. Hence why doesn't (+ 1 totalZeros) seem to be working? When I step through the debugger I can see that the totalZeros variable never changes. It is always zero...

(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)

の値に 1 を追加していますが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

上記は問題を解決しますが、利用可能な手順を利用していません。実際、問題を解決するための推奨される方法は、既存の機能を再利用することです。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 に答える