Return from a nested loop in Common Lisp
Asked Answered
M

3

5

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?

Mattiematting answered 25/12, 2012 at 7:9 Comment(0)
O
12

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))))
Orvilleorwell answered 25/12, 2012 at 7:29 Comment(0)
C
9

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.

Committee answered 25/12, 2012 at 8:52 Comment(0)
J
2

I think your solution should work with little adjustment while trying to keep the original form of the python code

(loop named outer for a from 1 below 1000 do
 (loop for b from a below 1000
    for c = (sqrt (+ (expt a 2) (expt b 2)))
    for s = (+ a b c)
    if (= s 1000) do (return-from outer (* a b c))))

And if you wanted to enter infix equations, you can use infix library available from quicklisp with (ql:quickload :infix), and then modify the above to get

(loop named outer for a from 1 below 1000 do
 (loop for b from a below 1000
    for c = #i(sqrt (a^^2 + b^^2))
    for s = #i(a + b + c)
    if (= s 1000) do (return-from outer #i(a * b * c))))
Jordans answered 18/12, 2013 at 14:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.