Account Options

  1. Sign in
The old Google Groups will be going away soon, but your browser is incompatible with the new version.
Google Groups Home
« Groups Home
new fn: juxt - Theory & application
There are currently too many topics in this group that display first. To make this topic appear first, remove this option from another topic.
There was an error processing your request. Please try again.
flag
  4 messages - Collapse all  -  Translate all to Translated (View all originals)
The group you are posting to is a Usenet group. Messages posted to this group will make your email address visible to anyone on the Internet.
Your reply message has not been sent.
Your post was successful
 
From:
To:
Cc:
Followup To:
Add Cc | Add Followup-to | Edit Subject
Subject:
Validation:
For verification purposes please type the characters you see in the picture below or the numbers you hear by clicking the accessibility icon. Listen and type the numbers you hear
 
Sean Devlin  
View profile  
 More options Dec 18 2009, 2:30 am
From: Sean Devlin <francoisdev...@gmail.com>
Date: Thu, 17 Dec 2009 23:30:06 -0800 (PST)
Local: Fri, Dec 18 2009 2:30 am
Subject: new fn: juxt - Theory & application
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")

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))

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 must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Laurent PETIT  
View profile  
 More options Dec 18 2009, 4:17 am
From: Laurent PETIT <laurent.pe...@gmail.com>
Date: Fri, 18 Dec 2009 10:17:04 +0100
Local: Fri, Dec 18 2009 4:17 am
Subject: Re: new fn: juxt - Theory & application

Hello,

2009/12/18 Sean Devlin <francoisdev...@gmail.com>

Which version of juxt are you using ? Mine (from branch 1.1.x) returns a
vector, not a list/seq

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.


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Sean Devlin  
View profile  
 More options Dec 18 2009, 8:56 am
From: Sean Devlin <francoisdev...@gmail.com>
Date: Fri, 18 Dec 2009 05:56:58 -0800 (PST)
Local: Fri, Dec 18 2009 8:56 am
Subject: Re: new fn: juxt - Theory & application
Laurent,
1.  You are correct.  juxt returns a vector.  This is based on some
old articles I wrote, and I must of missed those references.
2.  Guilty :)  The partial is (deliberate) overkill.

Sean

On Dec 18, 4:17 am, Laurent PETIT <laurent.pe...@gmail.com> wrote:


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Alex Osborne  
View profile  
 More options Dec 18 2009, 11:04 pm
From: "Alex Osborne" <a...@meshy.org>
Date: Sat, 19 Dec 2009 15:04:09 +1100
Local: Fri, Dec 18 2009 11:04 pm
Subject: Re: new fn: juxt - Theory & application
Just tossing up some non-juxt alternatives for comparison's sake, so we
can see where it is an improvement.

Sean Devlin <francoisdev...@gmail.com> writes:
> 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")

(map test-map [:a :c])

> 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)

[(:a test-map) (parse-int (:c test-map))]

> 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

(let [ks [:a :b]]
  (= (map {:a 1 :b  2 :c 3} ks)
     (map {:a 1 :b 34 :c 3} ks)))

> 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))

(for [i (range 1 6)] [i (* i i)])

> ;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>

(group-by #(fmap % [:sold-by :category]) sales-coll)

 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
End of messages
« Back to Discussions « Newer topic     Older topic »