I'm working on a spell checker that attempts to suggest corrections from a given dictionary. One of the heuristics is to see if inserting a character at each point in the given string results in a recognized word. So I have an outer loop that moves across each position in the string and an inner loop that tests a-z at that point. In Common Lisp I use this: (defun word-insertion (s) (let ((s1 (make-string (1+ (length s))))) ; Copy the input and make room for an extra char (setf (subseq s1 1 (length s1)) s) (dotimes (i (length s1) nil) ; Outer loop (unless (zerop i) (setf (char s1 (1- i)) (char s (1- i)))) (dotimes (j (1+ (- (char-code #\z) (char-code #\a)))) ; Inner loop (setf (char s1 i) (code-char (+ j (char-code #\a)))) (let ((index (binary-search s1))) ; Check in the dictionary for a match (when index (return-from word-insertion index)))) ))) ; Done if match found
The main point is that I can use two DOTIMES forms, one nested inside the other, and I can exit either at any point. I actually exit the entire function as soon as I find a match via RETURN-FROM. Clojure has 'dotimes', but from what I understand there is no way to exit prematurely? The obvious alternative is to nest a couple of 'loop' forms: (defn g [p q] (loop [i 0] (if (= i p) nil (do (loop [j 0] (if (= j q) nil (do (prn (list i j)) (recur (inc j)))) ) (recur (inc i)))) )) The loop/recur pairs seem to establish outer and inner recursion points (I can't really tell from the macro expansion), and this function behaves as expected. This approach appears to be equivalent to something like this: (defn f [p q] (letfn [(outer [i] (if (= i p) nil (do (inner i 0) (outer (inc i)))) ) (inner [i j] (if (= j q) nil (do (prn (list i j)) (inner i (inc j)))) )] (outer 0))) Again the important thing is that I can terminate the inner loop based on my own condition. However, it seems that in the outer loop I have to capture the value of the inner loop directly. I can't simply leave both loops: (defn word-insertion [s] (let [s1 (make-array Character/TYPE (inc (count s)))] (System/arraycopy (.toCharArray s) 0 s1 1 (count s)) (loop [i 0] (if (= i (count s1)) nil (do (when-not (zero? i) (aset s1 (dec i) (nth s (dec i)))) (let [match (loop [j 0] (if (= j (inc (- (int \z) (int \a)))) nil (do (aset s1 i (char (+ j (int \a)))) (let [match (binary-search (String. s1))] (if match match (recur (inc j)))) )))] (if match match (recur (inc i)))) )))) ) One other version I considered makes due with a single 'loop', but this is pretty convoluted: (defn word-insertion [s] (let [s1 (make-array Character/TYPE (inc (count s)))] (System/arraycopy (.toCharArray s) 0 s1 1 (count s)) (loop [i 0 j 0] (when (and (not (zero? i)) (zero? j)) (aset s1 (dec i) (nth s (dec i)))) (cond (= i (count s1)) nil (= j (inc (- (int \z) (int \a)))) (recur (inc i) 0) :else (do (aset s1 i (char (+ j (int \a)))) (let [match (binary-search (String. s1))] (if match match (recur i (inc j)))) )))) ) The one nice thing about this is I can terminate the entire loop and return a value in one step. Otherwise the logic is a mess. Any suggestions out there? Aloha, David Sletten --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en -~----------~----~----~----~------~----~------~--~---