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 [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
-~----------~----~----~----~------~----~------~--~---