Search code examples
lispclisp

Sum of odd and even numbers


I'm new to lisp programming and I'm trying to create a program that accept six numbers and check whether each number is either odd or even number.


(princ"Input six number: ")
(setq a(read))
(setq b(read))
(setq c(read))
(setq d(read))
(setq e(read))
(setq f(read))
(format t "~% ~d" a)
(format t "~% ~d" b)
(format t "~% ~d" c)
(format t "~% ~d" d)
(format t "~% ~d" e)
(format t "~% ~d" f)
(if(= 0(mod a 2))
   (print"even")
   (print"odd"))
   (if(= 0(mod b 2))
      (print"even")
      (print"odd"))
      (if(= 0(mod c 2))
         (print"even")
         (print"odd"))
         (if(= 0(mod d 2))
            (print"even")
            (print"odd"))
             (if(= 0(mod e 2))
                (print"even")
                 (print"odd"))
                 (if(= 0(mod f 2))
                    (print"even")
                    (print"odd"))
                    (terpri)

Solution

  • You have a lot of code that looks like this:

    (if(= 0(mod ... 2))
       (print"even")
       (print"odd"))
    

    (this might be a copy/paste problem but in your question they are indented more and more to the right. They are however not nested, they are all at the same depth (they are toplevel expressions) so by convention they should not be indented).

    A first step would be to factor them using a function like this one:

    (defun check-even-odd (number)
      (if (= 0 (mod number 2))
          (print "even")
          (print "odd")))
    

    The above defines a function named check-even-odd of one parameter number, and it applies the same logic you originally had for any arbitrary number.

    The rest of your code can be simplified as:

    (check-even-odd a)
    (check-even-odd b)
    (check-even-odd c)
    (check-even-odd d)
    (check-even-odd e)
    (check-even-odd f)
    

    Now, you can define two additional global variables:

    (defparameter total-even 0)
    (defparameter total-odd 0)
    

    Each of them holds a sum, and is initialized to 0.

    You can rewrite the check-even-odd function as follows to update the counters. First of all, let's just rewrite the current code by using cond, since we are going to need to perform multiple actions in each case, and if only accepts one expression for each branch (the combination if and progn is a bit ugly):

    (defun check-even-odd (number)
      (cond
        ((= 0 (mod number 2))
         (print "even"))
        (t
         (print "odd"))))
    

    This above behaves as the original code.

    In order to increment a variable by a certain amount, you can use INCF:

    (defun check-even-odd (number)
      (cond
        ((= 0 (mod number 2))
         (print "even")
         (incf total-even number))
        (t
         (print "odd")
         (incf total-odd number))))
    

    When you execute your whole script, the total will be initialized to zero, then each call to check-even-odd will add the number to the appropriate counter.

    Notes:

    • You may find other places where you can use functions to abstract duplicated code
    • You should use defparameter instead of setq when initializing a, b, etc, because otherwise the variables are not declared and calling setq on undeclared variables is not standard
    • In fact, it is possible to rewrite the whole program without having any global state, this could be a good next exercise
    • You can generalize for less or more numbers instead of 6, you would need to write a loop or a recursive function to repeat the same code an arbitrary amount of time
    • Input/output may need to be flushed (see finish-output, clear-input) otherwise you could experience strange behavior when the underlying stream is buffered.