Hi Michael,

Larry recently posted something similar
http://groups.google.com/group/clojure/browse_thread/thread/773e628953b40d9f
Which generated also quite a lot of discussion which you might also be
interested in.

> (def matrix #{[-1 -1] [-1 0] [-1 1] [0 -1] [0 0] [0 1] [1 -1] [1 0] [1 1]})
> (defn neighbours
>    "All direct neighbours around [pos] and pos itself"
>    [pos]
>    (defn translate [[x y]] [(+ x (first pos)) (+ y (second pos))])
>    (map translate matrix)
> )

Nothing wrong with it, but using def or defn inside a defn exposes a
new global var. In this case 'translate' is now a global function
which will have values relative to the last time neighbours was
called. You could make it locally scoped by doing something like:
(let [matrix #{.....}]
  (defn neighbours
    "All direct neighbours around [pos] and pos itself"
    [pos]
    (let [translate (fn [[x y]] ......)]
      (map translate matrix))))
This is not really any nicer I'm only bringing it up to make sure you
are aware of the scoping implications of using defn (or def) inside a
function.
You can write an equivalent function without using matrix or
translate:
(defn neighbours
  "All direct neighbours around [pos] and pos itself"
  [[x y]]
  (for [dx [-1 0 1] dy [-1 0 1]] [(+ x dx) (+ y dy)]))

>             new-board (map
>                        (fn [[x y]] (if (alive [x y] board) [x y] nil))
>                        (all-neighbours bsize board))
>             ]

It might have been more convenient to define alive such that instead
of returning a boolean, it returns pos or nil. Then you could avoid
wrapping it in an anonymous function and just do
(map alive (all-neighbours bsize board))


>              (set (filter #(not (nil? %)) new-board))))

You can use the 'identity' function instead of not nil? to be more
concise:
user=> (filter identity [1 nil 2])
(1 2)


> (defn to-string
>      "creates a string representation of a board"
>      ([board] (to-string size board))
>      ([bsize board]
>    (def axis (range bsize))
>    (reduce
>     (fn [text x]
>         (str text (reduce
>         (fn [text y]
>             (str text (if (contains? board [x y]) "#" "_"))
>             )
>             "" axis)
>          "\n")) "" axis)))

; untested but I think you could write this along the lines of:
(str (for [i (range bsize)]
        (concat \newline
          (for [j (range bsize)]
            (if (contains? board [i j]) "#" "_"))))


> (defn demo
> "runs a simple board 10 times"
> []
> (map
>   #(println (to-string %))
>   (take 10 (iterate next-board start-board))
> ))

map creates a lazy sequence. for side-effects to be realized the
sequence needs to be forced. This can be a bit of a trap if you are
expecting side-effects (like printing) but they never occur. Consider
using doseq instead of map in such a scenario:
(doseq [b (take 10 (iterate next-board start-board))]
  (println (to-string b)))


Regards,
Tim.


--~--~---------~--~----~------------~-------~--~----~
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
-~----------~----~----~----~------~----~------~--~---

Reply via email to