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)))
6
  • 2
    (+ 1 totalZeros) adds 1 to totalZeros but discards the result. It would be like saying totalZeros + 1; in C without assigning it. You could use (setq totalZeros (+ totalZeros 1)) or (incf totalZeros). Commented Oct 20, 2013 at 10:28
  • 1
    You've implemented a recursive solution (which is the functional thing to do) but your recursive function isn't returning anything. Instead of trying to modify shared state (which is not the functional thing to do) you should return the count from the recursive function. Commented Oct 20, 2013 at 10:46
  • @mbratch As this seems to be scheme, set! has to be used instead of setqor incf Commented Oct 20, 2013 at 11:02
  • Yes, I am indeed using Scheme, I should have been more specific... Thanks so much for the comments everyone. My background is C style languages. Definitely a brain fart on this one. Works fine now. Commented Oct 20, 2013 at 18:02
  • possible duplicate of Not returning the answer i need Commented Oct 20, 2013 at 20:28

1 Answer 1

3

The problem is that this expression:

(+ 1 totalZeros)

Is adding one to the value of totalZeros, but then does nothing with the result, so it's lost. Are you familiar with other programming languages? the above is the same as doing this, in a C-like language:

totalZeros + 1;

Clearly, if you don't store the result of the addition somewhere, the value is discarded. Going back to your code, if you intend to store the addition in the same variable (like a totalZeros++; expression would do), this is the way to write it in Scheme:

(set! totalZeros (+ 1 totalZeros))

In fact, by using the above line your code will work. Although it's possible to write a correct program in a procedural style like that - defining a local variable and mutating its value as you go, it's not recommended. That's correct for a C-like language, but it's not the way you think about a solution in Scheme, normally you'd pass along the modified value as a parameter to a function call; this is an equivalent, more idiomatic solution:

(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

Notice how null? is used to determine if a list is empty (instead of using length), and see how the procedures zero? and add1 are used. Pay attention to how the totalZeros counter is passed along as a parameter, how it's initialized to 0 when the iterator is called, and how it's returned at the end of the recursion, when the list is empty. Also notice how cond is useful when there are several conditions to consider, and the fact that a function should return a value, only using display to print that value after it's called.

The above will solve the problem, but it's not making use of available procedures. In fact, the preferred way to solve a problem is to reuse existing functionality. In Racket you could simply call the count procedure, telling it to count all the zeros found in the list:

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

(display (countZeros '(1 2 0 3 0 4 5 0 6 0 7 0 0)))
=> 6
Sign up to request clarification or add additional context in comments.

2 Comments

Yeah you can definitely tell my code has a C style logic to it as background is in C based languages. I am not sure why I was thinking (+ 1 totalZeros) was actually storing and updating the current value with 1. As you said, set! works perfect since I am using Scheme. Your example in general just made a lot of things click for me. I definitely appreciate you taking the time to post what you did. One thing I am unsure of, using an if statement there always has to be an else part correct? Hence why I was using when... cond only needs one statement following it? Why not when instead of cond?
@user2899772 in Racket if must have an else part, and if you need only a single condition, when must be used. On the other hand, cond is like a series of if-else if-else if-else statements, and has the added benefit of having an implicit begin, meaning that you can put more than one expression in each condition. The same is true for when: you can put more than one expression inside, whereas if limits you to a single expression in each leg.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.