-1

I've been working on a project in common lisp for a bit now, and I can't figure out why the loop I am using won't return a list. It will print the new list (correctly!) if I use a 'Finally' statement at the end of the loop, but it will not print outside of it or let me use it for anything.

All of the examples I have found indicate that a return statement should do it, but still no dice when I try that. It just tells me meansList is undefined when I try to use it outside of the loop, and initializing it there doesn't work either.

The end goal is for the loop to return a list of the mean values for each set of data elements.

    (defparameter data
                     ' ((2.0 8.0) (0.9 1.2) (6.0 2.0)
                       (7.0 3.5) (4.0 6.0) (1.0 4.0)))

    (loop for i in data
      do (setq j (mean i)) collect j into meansList
      finally (return (meansList))

The mean function returns the mean of a list. I have checked several times and that works as intended, though I could provide it here if necessary.

kra361
  • 1
  • 1
    This falls into category of "caused by a typo" issue; superfluous parentheses around a variable to be evaluated, turning it into a function call. – Kaz Oct 29 '20 at 20:43

1 Answers1

3

(meansList) means apply the function meansList without arguments. Since Common Lisp is a Lisp2 you'd get an error that the function meansList does not exist. If you know C type languages it is if you would do something like this:

int c = 10;
return c();  // is this the variable that turns into 10? 

You should also consider using *earmuffs* for your global variables since they become dynamic. If you ever have a parameter called data that calls a function that relies on the global data it will be temporarily changed and even in medium projects it would be like searching for a needle in a haystack.

Also note that loop creates a block called nil and return uses the closest block named nil so you are returning from loop. eg. it becomes the evaluation of the loop. To return from a function that uses the loop you need to use (return-from function-name whatever-expression-to-compute-value)

I also see there is a mutation of j which is uneccessary. It could be written like this:

(loop :for i :in *data*
      :collect (mean i) :into meansList
      :finally (return meansList))

If you collect anything without mentioning where it will also return it so this is the same:

(loop :for i :in *data*
      :collect (mean i))

Chapter Loop for black belts in Practical Common Lisp is quine nice with examples and The Loop macro in CL Cookbook

Sylwester
  • 44,544
  • 4
  • 42
  • 70
  • (loop for i in *data* collect (mean i) into meansList) Like this? This doesn't seem to work either. It's still telling me the value for meansList doesn't exist when I try to print it. Also, if you don't tell it where to return it to, how can you use it later? – kra361 Oct 28 '20 at 23:50
  • @kra361 `meansList` is only accessable from within the loop. It is the result of the form which is what was the list of collected values in both the forms. You can `(print (loop ...))` or you can `(let ((ml (loop ...))) (print ml))` – Sylwester Oct 29 '20 at 01:05
  • @kra361 as an addition: this code can be just `(mapcar #'mean *data*)` – leetwinski Oct 29 '20 at 10:54
  • I think I just misunderstood how output from loops worked in this instance. After looking into the mapcar bit, it's a lot closer to what I wanted. – kra361 Oct 29 '20 at 17:09