title: Returning from a function while inside one or more nested loops?
body: <p>Is there a way to immediately return from a function when in one or more nested loops?</p>
  
  <p>Here's some sample code illustrating the problem:</p>
  
  <pre><code>; Grid data structure
  ; -------------------
  (defstruct grid :width :height)
  
  (defn create-grid [w h initial-value]
    (struct-map grid
      :width  w
      :height h
      :data   (ref (vec (repeat (* w h) initial-value)))))
  
  (defn create-grid-with-data [w h gdata]
    (struct-map grid
      :width w
      :height h
      :data (ref gdata)))
  
  (defn get-grid [g x y]
    (let [gdata (g :data)
          idx   (+ x (* (g :width) y)) ]
      (gdata idx)))
  
  (defn set-grid [g x y value]
    (let [data  (deref (g :data))
          idx   (+ x (* (g :width) y)) ]
      (dosync (alter (g :data) (fn [_] (assoc data idx value))))))
  
  (defn get-grid-rows [g]
    (partition (g :width) (deref (g :data))))
  
  
  
  ; Beginning of test app
  ; ---------------------
  
  ; The Tetris playing field  
  (def current-field (create-grid 20 10 0))
  
  
  ; A tetris block (the L-Shape)
  (def current-block {
    :grid (struct-map grid :width 3 :height 3 :data [ 0 1 0
                                                      0 1 0
                                                      0 1 1 ])
  
    ; upper-left corner of the block position in the playing field
    :x (ref 0) 
    :y (ref 0)
  } )
  
  
  ; check-position-valid checks if the current position
  ; of a block is a valid position in a playing field
  (defn check-position-valid [field block]
    (dotimes [ x ((block :grid) :width) ]
      (dotimes [ y ((block :grid) :height) ]
        (if
          (let [ g           (block :grid)
                 block-value (get-grid g x y)
                 field-x     (+ x (deref (block :x)))
                 field-y     (+ y (deref (block :y))) ]
            (if (not (zero? block-value))
              (if-not
                (and (&gt;= field-x 0)
                     (&lt; field-x (field :width))
                     (&lt; field-y (field :height))
                     (zero? (get-grid field field-x field-y)))
                false ; invalid position, function should now return false
                true ; ok, continue loop
                )))
          true
          false))))
  
  (println (check-position-valid current-field current-block))
  </code></pre>
  
  <p>Perhaps I'm approaching the problem too much in an imperative way.</p>
  
  <p><b>Update</b><br>
  Ok, I found a solution:</p>
  
  <pre><code>; check-position-valid checks if the current position
  ; of a block is a valid position in a playing field
  (defn check-position-valid [field block]
    (let [stop-condition (ref false)]
      (loop [ x 0 ]
        (when (and (not (deref stop-condition))
                   (&lt; x ((block :grid) :width)))
          (println "x" x)
          (loop [ y 0 ]
            (when (and (not (deref stop-condition))
                       (&lt; y ((block :grid) :height)))
              (println "y" y)
              (let [ g           (block :grid)
                     block-value (get-grid g x y)
                     field-x     (+ x (deref (block :x)))
                     field-y     (+ y (deref (block :y))) ]
                (if (not (zero? block-value))
                  (if-not
                    (and (&gt;= field-x 0)
                         (&lt; field-x (field :width))
                         (&lt; field-y (field :height))
                         (zero? (get-grid field field-x field-y)))
                    (do
                      (println "stop is true")
                      (dosync (alter stop-condition (fn [_] true)))))))
              (recur (inc y))))
          (recur (inc x))))
      (not (deref stop-condition))))
  
  (println (check-position-valid current-field current-block))
  </code></pre>
  
  <p>It uses a mutable reference as a stop flag, breaking the functional style of programming. But I'm happy to have a solution. Feel free to share a better way.</p>
  
  <p><b>Update</b><br>
  For those interested, I've finished a first version version of my <a href="http://stacked-crooked.googlecode.com/svn/trunk/PlayGround/Clojure/Tetris.clj" rel="nofollow noreferrer">Clojure Tetris</a> game. Feel free to give it a try :)</p>