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

Reply via email to