Quantcast

Maximum PC

It is currently Mon Sep 01, 2014 3:40 am

All times are UTC - 8 hours




Post new topic Reply to topic  [ 2 posts ] 
Author Message
 Post subject: C# LINQ, Java Quaere, Ruby & Clojure Presentation
PostPosted: Mon May 24, 2010 4:30 pm 
Bitchin' Fast 3D Z8000*
Bitchin' Fast 3D Z8000*
User avatar

Joined: Tue Jun 29, 2004 11:32 pm
Posts: 2555
Location: Somewhere between compilation and linking
While looking for something completely unrelated, I stumbled upon this presentation that demonstrates LINQ query functionality in Java using Quaere and by adding the same/similar functionality using macros in Ruby and Clojure. The example query selects strings of length 5 from an array, upcases and sorts the result set. Pretty basic stuff. If anyone has a better example query, I'd be interested in hearing about it.

The LINQ version of the query resembles SQL, but the select "clause" is at the end of the query. The other examples do things in the same order... no biggie.

Frankly, the Quaere version of the query is ugly enough that I would actually be reluctant to use it, which is a shame because it might be a capable query framework (-- I'm assuming that is what people are calling them). I hate ugly code. It's not only painful to review, but also harder to remember.

The Ruby version was implemented using a macro, and the query is rather elegant looking; however, the macro code is horrible. At one point, I thought that I might want to add Ruby to my tool belt... after reviewing the language a bit more, I think that they should rename it COAL, because it sure as hell doesn't remind me of a ruby.

In contrast to the Ruby implementation, the Clojure query is a bit less clear (at least to my eye -- I haven't taken it upon myself to learn Clojure yet), but the actual macro is light-years more understandable (3 SLOC vs 40 or 50 SLOC). This is appears to be the biggest complaint about Ruby from Lisp folks -- the macro system is horribly broken when you try to do some pretty basic things with it.

Anyways, as I mentioned before, this query is brain dead simple and I probably wouldn't write a macro unless I was going to be performing this type of query pretty darn frequently. Below is the CL code for performing the same query -- I used a mapping function with write-to-string to save me the trouble of typing everything inside of double quotes.

Code:
CL-USER> (defvar names (mapcar #'write-to-string '(burke connor frank everett albert george harris david)))
NAMES
CL-USER> (defvar query (sort (mapcan #'(lambda (x)
                (if (= (length x) 5)
                    (list (string-upcase x)))) names)
              #'string<))
QUERY
CL-USER> query
("BURKE" "DAVID" "FRANK")


Top
  Profile  
 
 Post subject:
PostPosted: Mon May 24, 2010 5:27 pm 
Bitchin' Fast 3D Z8000*
Bitchin' Fast 3D Z8000*
User avatar

Joined: Tue Jun 29, 2004 11:32 pm
Posts: 2555
Location: Somewhere between compilation and linking
Temptation got the better of me and I decided to write a query macro just "because it was there". A logical place to start when writing a macro is to write a somewhat equivalent function and see how that looks...

Code:
(defun query (&key select from where)
  (mapcar select (mapcan where from)))

(query :select (lambda (x) (print (string-upcase x)))
       :from names
       :where (lambda (x) (if (= (length x) 5) (list x))))

"BURKE"
"FRANK"
"DAVID"
("BURKE" "FRANK" "DAVID")

While lambda functions are powerful, I don't really like having to write them in the query like I did above nor do I like telling mapcan that results satisfying the length predicate need to be placed in a list. Something like this is much more readable...

Code:
(query :select (print (string-upcase x))
       :from names
       :where (= (length x) 5))


I'm at Starbucks at the moment w/o my Lisp reference manual, so I'm going to cheat just a bit and require the user to use "x" as their variable names in the queries. Given that constraint, the following macro seems to work...

Code:
(defmacro query (&key select from where)
  `(mapcar (lambda (x) ,select)
    (mapcan (lambda (x) (if ,where (list x))) ,from)))

(query :select (print (string-upcase x))
       :from names
       :where (= (length x) 5))

"BURKE"
"FRANK"
"DAVID"
("BURKE" "FRANK" "DAVID")

(query :select (reverse (string-downcase x))
       :from names
       :where (< (length x) 6))
("ekrub" "knarf" "divad")  ;Notice that I told it to reverse the strings in the select clause

(query :select (string-upcase x)
       :from names
       :where (eq (char x 0) #\A))
("ALBERT")

(query :select (string-upcase x)
       :from names
       :where (or (= (length x) 5)
            (= (length x) 6)))
("BURKE" "CONNOR" "FRANK" "ALBERT" "GEORGE" "HARRIS" "DAVID")

Cool... pretty general and does most of the things that I would specify in a query. Maybe I'll screw around sometime and see what it takes to do a join.


Top
  Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 2 posts ] 

All times are UTC - 8 hours


Who is online

Users browsing this forum: No registered users and 2 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group