Common Lisp `loop`: maximize into local variable introduced by `let`

1.2k views Asked by At

The loop facility in Common Lisp allows several value accumulation clauses, maximize amongst others.
Now, it is also possible to give a variable var to the maximize clause:

(loop for x from 0 to 10 maximize (func x) into var)

My question is:

Is it possible to give as var a new local variable introduced by let?

An example scenario would be:

(let ((var -1)) ; assume numeric result
  (loop for x from 0 to 10 maximize (func x) into var))

It is not important that x has a numeric value, it's only for illustration purposes.

1

There are 1 answers

4
sds On BEST ANSWER

Mix bindings?

No, the into variables are bound by loop.

What you can do is bind your var to the return value of loop:

(let ((var (loop for x from 0 to 10 maximize (func x))))
  ;; use var here
  ...)

Complex loop - use multiple values, functional style

If you are doing many things in a single loop, you might want to use values function in Common Lisp:

(multiple-value-bind (max min sum)
    (loop for x from 0 to 10
      maximize (f1 x) into max
      minimize (f2 x) into min
      sum (f3 x) into sum
      finally (return (values max min sum)))
  ;; use max, min and sum here
  ...)

Note that the variables max, min and sum bound by multiple-value-bind and loop are completely separate and independent, and have absolutely nothing in common and are named the same for didactic purposes only.

If you rename them (as you definitely should for the sake of code readability!):

(multiple-value-bind (max min sum)
    (loop for x from 0 to 10
      maximize (f1 x) into max1
      minimize (f2 x) into min1
      sum (f3 x) into sum1
      finally (return (values max1 min1 sum1)))
  ;; use max, min and sum here
  ...)

and recompile your code, you will see that the disassembly is identical.

Complex loop, use finally, procedural style

As suggested by @coredump, you can set your variables in the finally construct:

;; bind max, min and sum
(loop for x from 0 to 10
  maximize (f1 x) into max1
  minimize (f2 x) into min1
  sum (f3 x) into sum1
  finally (setq max max1
                min min1
                sum sum1))
;; use max, min, and sum; max1 et al do not exist here

Generally, speaking, there is more than one way to skin the cat here...