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)



Attachment: signature.asc
Description: Message signed with OpenPGP using GPGMail

Reply via email to