Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Return from a nested loop in Common Lisp

I'm trying to convert this Python code into Common Lisp:

for a in xrange(1,1000):
    for b in xrange(a,1000):
        c = (a**2 + b**2) ** 0.5
        s = a + b + c
        if s == 1000:
            return a * b * c

My first attempt was:

(loop for a from 1 to 999
      do (loop for b from a to 999
               for c = (sqrt (+ (expt a 2) (expt b 2)))
               for s = (+ a b c)
               until (= s 1000)
               finally return (* a b c))))

This doesn't work. My task is: when s hits 1000 make the whole expression above return (* a b c). How to return some value from a nested loop macro?

like image 980
Mirzhan Irkegulov Avatar asked Nov 30 '22 22:11

Mirzhan Irkegulov


2 Answers

You can use block and return-from operators: block establishes a named block of code, and you can return from this block with return-from using the name of the block

(let (c s)
  (block nested-loops
    (do ((a 1 (1+ a))) ((= a 999))
      (do ((b a (1+ b))) ((= b 999))
        (setf c (sqrt (+ (expt a 2) (expt b 2)))
              s (+ a b c))
        (if (= s 1000)
            (return-from nested-loops (* a b c)))))))

PS, I don't use loop here, I just got used to do.

Also from http://www.gigamonkeys.com/book/loop-for-black-belts.html

To allow RETURN-FROM to be used to return from a specific loop (useful when nesting LOOP expressions), you can name a LOOP with the loop keyword named. If a named clause appears in a loop, it must be the first clause. For a simple example, assume lists is a list of lists and you want to find an item that matches some criteria in one of those nested lists. You could find it with a pair of nested loops like this:

(loop named outer for list in lists do
     (loop for item in list do
          (if (what-i-am-looking-for-p item)
            (return-from outer item))))
like image 94
TheEnt Avatar answered Feb 04 '23 01:02

TheEnt


The Python return statement doesn't return from the loop, it returns from the whole function that the loop is contained in. In Common Lisp, a function establishes an implicit block with the same name as the function. So you can use:

(return-from function-name (* a b c))

to perform the return equivalent to the Python code.

like image 40
Barmar Avatar answered Feb 04 '23 02:02

Barmar