On May 23, 2014, at 2:19 AM, sorin cristea <srncris...@gmail.com> wrote: > Thank Philippe for your advices,I came from java environment and seems I > still remain with some 'bad' habits.
Coming from Java, the main thing to bear in mind in Clojure is that you do not have "variables" in the sense you are used to and you generally avoid "loops" in favor of operations on whole collections (such as map/reduce). `def` and `defn` create global bindings - they are not variable assignments - and you don't want `def` nested into `defn`. You can use `let` to create local bindings (again, not variables). Clojure has `future` built-in so you might consider something like this: (defn sample-fc [] (let [futures (repeatedly 3 (fn [] (future "task result !!!")))] (doseq [f futures] (println (deref f))))) Or just: (defn sample-fc [] (doseq [f (repeatedly 3 (fn [] (future "task result !!!")))] (println @f))) ;; @f is short for (deref f) `repeatedly` takes a count and a no-arg function and return a sequence of results of calling that function. Or if you want to see the results differ: (defn sample-fc [] (doseq [f (for [i (range 3)] (future (str "task result " i "!!!")))] (println @f))) But all of these are still procedural in that they loop over the data and print results, rather than constructing data structures and transforming them (and ultimately printing the result). Consider: (defn make-tasks [inputs] (for [i inputs] (future (str "task result " i "!!!")))) (defn join-tasks [tasks] (clojure.string/join "\n" (map deref tasks))) (println (join-tasks (make-tasks (range 3)))) Here we've separated out task creation (based on a sequence of inputs), task completion (gathering the results as a single string), and printing the result. Note that `map` is lazy so the actual task completion - deref - is forced by joining the results together since that is an eager operation. At this point you could also do: (-> (range 3) make-tasks join-tasks println) which makes the "pipeline" sequence of steps more obvious. Since we've broken things down into small steps - and I mentioned `map` being lazy - it's instructive to see what happens if we don't "force" the mapped sequence to be used: (do (map deref (make-tasks (range 3))) (println "DONE")) This will just print DONE (and nil, the result of calling `println`) but the tasks will not even be created because nothing uses them. You can prove this to your self by adding a `println` inside the `future` call like this: (future (do (println "RUNNING " i) (str "task result " i "!!!"))) There are several ways to "force" the mapped sequence to be used (realized). You could wrap it in a call to `doall`: (do (doall (map deref (make-tasks (range 3)))) (println "DONE")) This realizes the mapped sequence (but still throws away the result). You could use `dorun`: (do (dorun (map deref (make-tasks (range 3)))) (println "DONE")) This realizes the mapped sequence and returns nil (which is then thrown away). Or you could use `mapv` which produces a vector and is not lazy: (do (mapv deref (make-tasks (range 3))) (println "DONE")) Or you could simply loop over the tasks, calling deref and throwing the result away via `doseq` (which is why this is kind of procedural): (doseq [f (make-tasks (range 3))] (deref f)) `doseq` returns nil. Which you choose depends on what, if anything, you want to do with the result. Hope that helps? Sean Corfield -- (904) 302-SEAN An Architect's View -- http://corfield.org/ "Perfection is the enemy of the good." -- Gustave Flaubert, French realist novelist (1821-1880)
signature.asc
Description: Message signed with OpenPGP using GPGMail