On Aug 9, 2010, at 11:52 PM, chepprey wrote: > > (defn show [words] > (let [word (first words)] > (do > (println word) > (if (nil? word) > (println "DONE") > (recur (rest words)))))) > > (show '("some" "sample" "words")) > > ... this shows the 3 words, then DONE, and terminates.
Your program works but maybe not the way you think it does. The first issue is related to an idiosyncrasy of other Lisps compared to Clojure. It's easy to understand the basic behavior of 'first' and 'rest': (first '(a b c)) => a (rest '(a b c)) => (b c) However, what happens when we look at the empty list? (first '()) => nil (rest '()) => () Notice how Clojure returns two different values here. Other Lisps (such as Common Lisp) define FIRST/REST of the empty list to both be NIL (i.e., the empty list itself). So it is common in other Lisps to test for the end of a list using the equivalent of 'nil?', namely the function NULL. But in Clojure if we are traversing a list and looking for the end, the correct function is 'empty?'. (nil? '()) => false (empty? '()) => true Furthermore, in your example you are testing whether the current first element is nil rather than checking that the list itself is empty. Your test should be (if (empty? words) ...). Your program eventually terminated because once your list was empty the first element was evaluated to be nil as above. > > But originally, I was trying to use loop/recur. If I replace the > "let" with "loop" in the above code, it goes into an infinite loop. I > assume there's something different in the scoping/binding rules with > loop, but I can't find a good explanation of what. I read in > "Programming Clojure", regarding loop, that it "...works like let, > establishing bindings and then evaluating exprs..." > This is a separate issue. It is true that 'loop' establishes bindings, however, it is your responsibility to update those bindings on each iteration through the loop by means of the 'recur' form. Your 'recur' confuses the distinction between the variables 'words' and 'word'. On the initial loop iteration, the variable 'word' is assigned the value of the first element of 'words'. But on the next iteration (and all others) your recur passes the rest of 'words' as the new value of 'word'. So in your example we wind up with this: 1. word <- "some" 2. word <- ("sample" "words") Obviously this 2-element list is never 'nil?', and the recur form keeps reassigning the same value forever. Instead, you need to rebind the variable 'words' to subsequent tails of the original list: (defn show [words] (loop [l words] (println (first l)) (if (empty? l) (println "DONE") (recur (rest l))))) And you probably want to test for the end of list before you print anything: (defn show [words] (loop [l words] (if (empty? l) (println "DONE") (do (println (first l)) (recur (rest l)))) )) Have all good days, 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 Note that posts from new members are moderated - please be patient with your first post. 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