Dowgird's version is idiomatic, except I'd flip the order of arguments around. And I'd call it like this.
Up vote 3 down vote favorite share g+ share fb share tw.
I'm passing the name of a function for use in another method. (defn mapper m function (cond (= '() m) '() true (cons (function (first m)) (mapper (rest m) function)))) (println (map_ '((blue red)(green red)(white red)) #'first)) Is there a more idiomatic way to do this in clojure? Function hash clojure lisp idiomatic link|improve this question asked Aug 11 '10 at 11:21hawkeye2,2041344 85% accept rate.
2 I guess that the most idiomatic way to do this is to use the map function: (map first '((blue red) (green red) (white red))). – Jonas Aug 11 '10 at 12:46.
Prefer vectors to lists. You don't have to quote a vector most of the time, and it has better performance for a lot of things, like random access. Lists are used much more rarely in Clojure than in other Lisps.
Prefer keywords to quoted symbols. Keywords stand out as "constant strings" or enumerated values. Keywords in Clojure can belong to a namespace, so they have all the advantages of symbols.
And again, there's no need to quote keywords, which is nice. Quoted symbols are used pretty rarely in Clojure, unless you're writing macros. #'first is the var called "first"; first is the value of the var called "first", i.e.
The fn. In this case (#'first foo) and (first foo) give the same answer, but #'first does an extra dereference every time you call it. So don't do this unless you want that dereference to happen over and over.
There's usually no need to use #'. The built-in map is lazy, whereas yours isn't. The built-in map takes advantage of chunked seqs for better performance, whereas yours doesn't.
Idiomatic code doesn't have to be lazy or use chunked seqs, but keep in mind that the builtins have some of this magic going on. So it's good to take advantage. Rather than (= '() x), the idiomatic test for an empty seq is (seq x), which returns nil if x is empty.
Note that in Clojure, (= '() nil) is false. If you do ever need to use the empty list (which you should rarely need to do), you don't have to quote it. Just use ().
Built-in map takes the function argument first because it accepts multiple collection arguments. When a function takes multiple arguments, those arguments have to go last in the argument list. I think it reads better the other way too: "(map f coll): map this function across this collection".
There's no need to use cond if you only have two options. You can use if instead. And if one of the branches in your if returns nil, you can use when.
It's nice to use when and if when appropriate, because they signal your intentions to the reader immediately, whereas cond could do anything and forces the reader to read more. Rafa? Dowgird's version is idiomatic, except I'd flip the order of arguments around.
And I'd call it like this: user> (mapper first :blue :red :green :red :white :red) (:blue :green :white).
Agreed about flipping the arguments. Either that or (defn mapper coll f & args ...) with args passed as additional args to f so that things like (mapper 5 2 3 + 1) are possible. – Rafa?
Dowgird Aug 11 '10 at 20:37 Great collection of tips. – edbond Aug 12 '10 at 7:02.
I believe you got it mostly idiomatic. Clojure's own map uses: (defn mapper coll f (when-let s (seq coll) (cons (f (first s)) (mapper (rest s) f)))) I have shortened it severely - the original produces a lazy sequence, deals with multiple collections, chunked-seqs, etc. By the way - I assume you want to pass the actual function, not it's name. The coll and f are idiomatic arg names to represent collections and functions, respectively.
Your version looks good to me. The usual names you will see in the clojure code base is 'coll' for collections. I have also seen 'xs' which is the Haskell style, I think.
You may also refer to the Clojure library coding standards on various conventions. Coming back to the example: Two observations. Use :else for 'cond' as the escape condition, instead of the Common Lisp style 'T'.
Instead of assuming lists, think sequences. With these two in mind, if I rewrite your code: user> (defn mapper coll f (cond (not (seq coll)) nil :else (conj (mapper (next coll) f) (f (first coll))))) #'user/mapper user> (mapper '(1 2 3) #(* % %)) (1 4 9) user> (mapper 1 2 3 #(* % %)) (1 4 9) Note that conj does the "right thing" as far as collections are concerned. It adds the new element to the head of a list, to the tail of a vector and so on.
Also note the use of 'next' instead of the first/rest idioms in traditional lisp. 'next' returns a sequence of elements after the first element. So, empty-ness can be checked by seq'ing on the collection which will return nil for an empty list or an empty vector.
This way it works for all collections.
I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.