1

I'm trying to write a function that can calculate GPA. Now I can do limited calculation(only 3 ),but I stuck on how to calculate more , without using loop or recursion (that's the requirement of subject) how to expend nth function? like: (nth n) ,if so ,is that mean i need to write a lambda expression? As an newbie, I maynot describe the question clearly, really need some help..

Glist is grade points Clist is credit hours.

GPA=( gradepoint *credithour + gradepoint *credithour) / ( the sum of credithour) like: (3*1+3*2+4*1)/(1+2+1)

here is my code:

(defun gpa (Glist Clist)
     (format t "~3,2f~%" 
      (/ 
        (+(nth 0 (mapcar #' * Glist Clist))
          (nth 1 (mapcar #' * Glist Clist))
          (nth 2 (mapcar #' * Glist Clist)))
        (+ (nth 0 Clist)
           (nth 1 Clist)
           (nth 2 Clist))
                   );end "/"
                   );end "format" 
       (values)    );end 
roccia
  • 179
  • 11
  • Use standard indentation, and do not duplicate code to comment your parentheses (I mean, what the hell?). See for example: http://gigamonkeys.com/book/syntax-and-semantics.html#formatting-lisp-code – Svante Sep 09 '11 at 08:43

2 Answers2

7

EDIT

This seems like a good opportunity to emphasize some common (little c) Lisp ideas, so I fleshed out my answer to illustrate.


As mentioned in another answer, you could use a sum function that operates on lists (of numbers):

(defun sum (nums)
  (reduce #'+ nums))

The dot product is the multiplicative sum of two (equal-length) vectors:

(defun dot-product (x y)
  (sum (mapcar #'* x y)))

The function gpa is a simple combination of the two:

(defun gpa (grades credits)
  (/ (dot-product grades credits) (sum credits)))

The example from the question results in the answer we expect (minus being formatted as a float):

(gpa '(3 3 4) '(1 2 1))
> 13/4

There are a few things worth mentioning from this example:

  1. You should learn about map, reduce, and their variants and relatives. These functions are very important to Lisp and are very useful for operating on lists. map* functions generally map sequences to a sequence, and reduce usually transforms a sequence into to a single value (you can however use forms like (reduce #'cons '(1 2 3))).

  2. This is a good example of the "bottom-up" approach to programming; by programming simple functions like sum that are often useful, you make it easy to write dot-product on top of it. Now the gpa function is a simple, readable function built on top of the other two. These are all one-liners, and all are easily readable to anyone who has a basic knowledge of CL. This is in contrast to the methodology usually applied to OOP.

  3. There is no repetition of code. Sure, sum is used more than once, but only where it makes sense. You can do very little more to abstract the notion of a sum of the elements of a list. It's more natural in Scheme to write functions with functions, and that's a whole different topic. This is a simple example, but no two functions are doing the same thing.

Keith Layne
  • 3,688
  • 1
  • 24
  • 28
  • ohhhh that's really simple. why I didn't find this function.. anyway , thanks for help. I have to read more carefully.. – roccia Sep 09 '11 at 06:02
  • 1
    +1 Very nice with the "bottom-up" approach explanation. I wrote a similar type of answer, albeit less eloquently ;-), and for Scheme, quite recently: http://stackoverflow.com/questions/7313563/flatten-a-list-using-only-the-forms-in-the-little-schemer/7324493#7324493 And yes, the conclusion is that `reduce` (or `fold` in Scheme) is a very important operation. :-D – C. K. Young Sep 09 '11 at 13:02
  • Ah, I don't think I ever knew how to do a `foldr` in CL...by following my own link I figured it out, this was the example I wanted to use above: `(reduce #'cons :initial-value '() :from-end t) ==> `. [This](http://en.wikipedia.org/wiki/Fold_(higher-order_function) neatly shows how this is the identity function on lists, it just has clunky syntax in CL. – Keith Layne Sep 09 '11 at 14:34
  • @Chris Thanks for that link, I don't use Lisps too often, it was instructive. – Keith Layne Sep 12 '11 at 00:09
1

If you're using nth to traverse a list, you're doing it wrong. In this case, you might want to write a summing function:

(defun sum (items)
  (reduce #'+ items))
C. K. Young
  • 219,335
  • 46
  • 382
  • 435
  • @Rainer: Thanks! Updated. (I'm actually a Schemer, so I'm sometimes unaware of the "better way" to do things in CL. Though, in Scheme I'd use `reduce` too (it takes different arguments from the CL version though), so.) – C. K. Young Sep 09 '11 at 05:18