Passing a symbol as a function in clojure
I'm learning clojure and I've written a small function that given a directory pathname returns a sorted-map of files in descending order according to their mtimes. Here it is:
(defn get-sorted-mtimes [dir]
(loop [sm (sorted-map-by >)
lst (for [f (.listFiles (File. dir))]
(let [k (.lastModified f)
v (.getName f)]
[k v]))]
(if (seq lst)
(recur (assoc sm ((first lst) 0) ((first lst) 1))
(rest lst))
sm)))
My question is: is there a way to pass the comparator method as a symbol name to the function and make it sort by asc or desc order accordingly? I mean something like:
(defn get-sorted-mtimes [dir <sym>]
(loop [sm (sorted-map-by <sym>)
...
Also, is there a more clojuresque way of accomplishing this task?
Well, for the record, this is the final form of the function that does exactly what I need it to:
(defn get-sorted-mtimes [dir comp]
(loop [sm (sorted-map-by (comparator comp))
lst (for [f (.listFiles (File. dir))]
(let [k (.lastModified f)
v (.getName f)]
[k v]))]
(if (seq lst)
(recur (assoc sm ((fir开发者_StackOverflow社区st lst) 0) ((first lst) 1))
(rest lst))
sm)))
If the (comparator) function isn't used, you get a java.lang.ClassCastException exception.
>
is just a function like any other in Clojure. So there is nothing to stop you passing it as an argument.
In fact I'd say that is good Clojure style to do it this way. Clojure is a functional programming language at heart, so there's nothing wrong with using higher order functions where appropriate!
Some other minor suggestions:
- Use
comparator
instead of<sym>
as a name for your function parameter. I think that's more descriptive and also more consistent with Clojure's normal naming conventions. - You could also add another function parameter to determine what you are comparing so that you can pass a function like
get-mtime
(a simple function that returns the mtime of a file). - I would suggest making a sequence of files the input to the function rather than a directory. Then your function is more general and can del with things like e.g. recursive directory scans in exactly the same manner
- I'd suggest using
(into sm lst)
- much simpler than your big loop/if/recur construct!
Then you can do really nice things like (get-sorted-files (list-files-recursive dir) > get-mtime)
- or any similar combinations you can think of!
精彩评论