Hello, 2009/12/18 Sean Devlin <francoisdev...@gmail.com>
> Hello everyone, > Today I'd like to shed some light on a new funciton in 1.1, juxt. In > order to understand juxt(apose), I'd like to first talk about comp > (ose). Comp can be defined in terms of reduce like so: > > (defn my-comp [& fns] > (fn [args] > (reduce > (fn[accum f](f accum)) > (conj (reverse (seq fns)) args)))) > > Granted, this isn't 100% equivalent to the Clojure comp function, but > it is very, very close. What it demonstrates is that comp applies a > list of functions in series using reduce. After writing Clojure for a > while, one usually finds frequent need to apply a list of functions in > parallel using map. juxt can be defined as follows > > (defn juxt [& fns] > (fn[ & arg] (map #(apply % args) fns))) > > Notice that juxt creates a closure. The most straightforward case is > to *predictably* access multiple values from a map. > > user=>(def test-map {:a "1" :b "2" :c "3" :d "4"}) > > user=>((juxt :a :c) test-map) > ("1" "3") > Which version of juxt are you using ? Mine (from branch 1.1.x) returns a vector, not a list/seq > > However, as one works with maps more and more, situations arise where > it is desired to perform many operations on a map at once. For > example > > ;assume parse-int turns a string to an int appropriately > user=>((juxt :a (comp parse-int :c)) test-map) > ("1" 3) > > Since juxt returns a closure, it is very useful in any place one would > use a map operation as well. For example, this can make turning a > list of maps into a list of lists very easy. Also, this made it very > easy to determine if a sub-selection of a hash-map is equal to another > hash- map > > user=>(def test-juxt (juxt :a :c)) > user=>(= (test-juxt {:a 1 :b 2 :c 3}) (test-juxt {:a 1 :b 34 :c 3})) > true > > One thing that is very interesting is that this function allows one to > simulate the behavior of let in a point-free style. > > ;This is deliberate overkill for a small example > ;Generate a list of squares > ;Notice that the juxt fn uses the range twice > user=>((partial map (juxt identity #(* % %))) (range 1 6)) > ((1 1) (2 4) (3 9) (4 16) (5 25)) > We're used to you being in love with point-free style, but the above example really does not need to use partial ? (map (juxt (identity #(* % %)) (range 1 6)) ;-) Anyway thanks for sharing this since it's not in my zone of comfort so it's interesting stuff to think about. > > This also is useful when combined w/ clojure.contrib/group-by. > Suppose you have a sales database with a table in it. This table keep > tracks of each sale (:id), when it happened (:year, :quarter), who > sold it (:sold-by), and what category (:category) the product was > in. > > It is obviously useful to group items by who sold it, or what category > it was sold under. However, it is also interesting to see which > employees are selling which items. This is a grouping by :sold-by > AND :category. In order to get at this information we'd do the > following. > > ;Assume our sales data is a list of maps, in the sales-coll variable > ;returns a map with two element vectors as keys, a list of maps as the > vals. > user=>(group-by (juxt :sold-by :category) sales-coll) > <Lots-Of-Data> > > Now, what happens when you need to change how you group the data? > Instead of :sold-by & :category, you need :year & :quarter? juxt > makes it easy. > > user=>(group-by (juxt :year :category) sales-coll) > <Lots-Of-Different-Data> > > And finally, what happens when you need to break it down by all for > variables simultaneously? > > user=>(group-by (juxt :year :category :sold-by :category) sales-coll) > <Our-Last-Data-Sample> > > There are tons of other uses for juxt, and I would encourage you to > experiment and find out some of these uses yourself. I hope these > examples help everyone understand how to use the new operator. > > Happy Hacking, > Sean > > -- > 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 > Note that posts from new members are moderated - please be patient with > your first post. > To unsubscribe from this group, send email to > clojure+unsubscr...@googlegroups.com<clojure%2bunsubscr...@googlegroups.com> > For more options, visit this group at > http://groups.google.com/group/clojure?hl=en -- 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 Note that posts from new members are moderated - please be patient with your first post. 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