Вопрос

Using Common Lisp I am trying loop through a list of students and if the GPA is greater than or equal to 3.0 I want to push a 1 onto another list called equal_names. The problem I am having is the interpreter keeps saying the GPA in the comparison list is "not of type (or rational float)". Why am I getting this error?

Yes, this is for homework. Also this is my first time asking on here, so if you need anything else please let me know.

Sample of the list I am getting the GPA from, where the GPA is 2.307...:

(SETQ students (LIST  
    (LIST (LIST 'Abbott 'Ashley 'J) '8697387888 'NONE 2.3073320999676614))) 

The code I have written:

(setq gpa_count ())  

    (loop for x in students 
        if(>=  3.0 (cdr (cdr (cdr x))))  
            do(push '1 gpa_count))
Это было полезно?

Решение

Given a non-empty list cdr returns the tail of that list, i.e. the list that contains all the elements of the list but the first. The important thing to note is that it returns a list, not an element. That is (cdr (cdr (cdr x))) returns the list (2.30733...), not the float 2.30733.

Другие советы

The loop iterates the outer list. To understand the code in the loop you can look at the first element in students, which is:

'((Abbott Ashley J) 8697387888 NONE 2.3073320999676614)

Now we are going to orientate the list. Every time you pass an element add a d. Every time you pick a value or go to a list in the list you add an a.

To find how to access the number 2.307.... You look at the first element element in the list:

  • (Abbott Ashley J) d
  • 8697387888 d
  • NONE d

Now we are at the part that you are interested in, ie. (2.3073320999676614)), thus you add an a. Now order those in reverse and put a c in front and a r in the end.. It becomes cadddr In light of that your loop should be:

(setq students '(("Mary Larson" 333 NONE 1.1)
                 ("Mina Morson" 333 NONE 2.5) 
                 ("Magnus Outsider" 333 NONE 4.1)))
(setq gpa_count ())

(loop for x in students 
      if (>=  3.0 (cadddr x))   
      do (push '1 gpa_count))
gpa_count ; ==> (1 1) 

Another example:

(setq x (1 (2 3) (3 4 (5 6) 7))) ; ==> (1 (2 3) (3 4 (5 6) 7))

To get the 3*. We follow the parts. 1 == d, (2 3) == a, 2 ==d, 3* == a. In reverse: adad and add c and r to the ends ==> cadadr. thus:

(cadadr '(1 (2 3) (3 4 (5 6) 7))) ; ==> 3

To get the 5. we do the same 1 == d, (2 3) == d and then we have the list we want ==a. Then 3 ==d, 4 ==d, (5 6) ==a. The 5 is the first element == a. In reverse aaddadd. Now CL guarantees 4 letters accessors so we need to split it up in 4s from the right. Thus it becomes:

(caadr (cdaddr '(1 (2 3) (3 4 (5 6) 7)))) ; ==> 5

Now, without describing you can pick any number or list. Eg. to get (5 6) ddadda, in reverse and split up becomes (cadr (cdaddr x))

Hope it helps.

If your data format is consistent then

(fourth x)

will return the GPA.

Going further,

(setf (symbol-function 'gpa)(function fourth))

would provide

(gpa x)

as "an accessor" for the gpa in the data structure.

My CLISP 2.49 gives this error message:

*** - >=: (2.307332) is not a real number

Let's look at that error message: >=: (2.307332) is not a real number.

The error happens at the call to >= and one argument is a list of a number, not a number.

Since you try to extract the number from a list, does that extract work?

We see that you call CDR. CDR of a list returns a list. So there is the error. You need to extract the number from the list.

Btw., CLISP has commands like help, where, backtrace, ... to further investigate the problem. Just type help and return, without anything else, and you see a list of commands.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top