1

I'm having some troubles with Common Lisp. I want to do a code to find how many times the values of a list are over or under two limits. I want to do a sweep on a list and evaluate if the current value is over or under the limits.

The output shall be the list with two values, the number of values in the list larger than the upper limit, and the number of those under the lower limit. I tried with the following code:

(defun find-inlist 
       (y) 
  (setq upper 0)
  (setq lower 0) 
  (loop for element in y (if (< element 32)(+ lower 1)
                           (if (> elemen 212)(+ 1 upper))))
  (list upper lower))

I used the following test case but I got an error message that I don't understand:

> find-inlist '(18 75 31 180 270 52 10 215)

Error: LOOP keyword expected in (... (IF (< ELEMENT 32) 
(+ LOWER 1) (IF (> ELEMEN 212) (+ 1 UPPER))))
6
  • You might be interested in the counting X into Y loop form. Commented Nov 24, 2024 at 23:27
  • Anyways, you can only put arbitrary code in places the loop macro expects it. Maybe the examples in unixuser.org/~euske/doc/cl/loop.html will help give a better feel for how it works. Commented Nov 24, 2024 at 23:52
  • Please don't edit your post just to bump it. Perhaps see what to do if no-one answers. Commented Nov 25, 2024 at 5:56
  • @tripleee it says "Edit your question to provide status and progress updates." I guess saying "it's still not working" is kind of a status update... Commented Nov 25, 2024 at 14:15
  • Don't use global variables, bind local variables with LET. Commented Nov 25, 2024 at 20:51

3 Answers 3

4

Since I mentioned count/counting in a comment, here's a version using it. loop itself handles initializing and incrementing the counter variables automatically, instead of you having to do it by hand, making it very convenient (And self-contained).

(defun count-in-list (y)
  (loop for elem in y
        count (< elem 32) into lower ; every time this test is true lower is incremented
        count (> elem 212) into upper ; and upper for this test
        finally (return (list lower upper)))) ; maybe return multiple values instead of a list?
Sign up to request clarification or add additional context in comments.

1 Comment

The count into expressions are nice (which count only if condition is true)
3

Some annotations on your code.

(defun find-inlist (y)
  ;; upper and lower are not declared, if the Lisp environment is nice, at
  ;; best you are modifying global variables, which is not a good idea in
  ;; general. You can introduce new variables with (let ((upper 0) (lower 0))
  ;; ...) instead. Since you are using LOOP below, you can also start your
  ;; LOOP using: LOOP WITH UPPER = 0 AND LOWER = 0, which declares local
  ;; variables too.
  (setq upper 0)
  (setq lower 0)
  ;;
  (loop
    for element in y
    ;; (if ...) is an expression and produce a value, but what should be done of the value being
    ;; computed? Unless you instruct the LOOP macro to do something with it,
    ;; the value will be discarded. Here you have a syntax error because LOOP
    ;; expects a keyword, like DO, or COLLECT, etc.
       (if (< element 32)
           ;; (+ x y) computes "x + y", but does not update neither x nor y.
           ;; Maybe you wanted to assign the computed value to lower?
           ;;
           ;;     (setf lower (+ lower 1))
           ;;
           ;; If so, there is a shorthand notation, which is (incf lower)
           ;;
           (+ lower 1)
           ;; Same here
           (if (> elemen 212)
               (+ 1 upper)
               )))
  ;; If you use WITH in the LOOP declaration, then UPPER and LOWER won't be
  ;; visible here, but you can use FINALLY (RETURN (LIST ...)) in the LOOP.
  (list upper lower))

Also:

  • You wrote elemen which is a typo
  • (if x y) is better written as (when x y) (the same goes for unless when the then branch is nil.

(thanks @tripleee)

3 Comments

Also elemen is an typo.
If there is no else, perhaps prefer when over if
oh right, didn't notice that typo
2

The corrected form of your code with somewhat minimal edits is:

(defun find-OUTlist      ;; NB!! Naming should NOT be misleading
       (y
          &aux               ;; auxiliary declarations marker
          (upper 0)          ;; local variables 
          (lower 0) )        ;; with their initial values
  (loop for element in y
        DO                   ;; keyword required 
        (if (< element 32) 
            (setf lower (+ lower 1))         ;; affect the value change
            (if (> element 212) 
                (setf upper (+ 1 upper)))))  ;; affect the value change
                         ;; CLHS: "Else-form-- The default is nil."
  (list lower upper))    ;; NB! More natural order

This code actually counts the elements which are OUTSIDE the range, and should not be named "...-inlist", which is misleading.

The return value is preferably given in the more natural, increasing order.

Comments

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.