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?

3 Answers 3

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))))
Sign up to request clarification or add additional context in comments.

Comments

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.

Comments

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))))

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.