Common Lisp Macro to T-Sql Experiment

So just another jump into the unknown, I wondered great wonders about creating a macro in Common Lisp that would just print out what I type between the () into T-Sql. Essentially, I want to type this:

(select user.name age)

And get:

"SELECT user.name, age"

Now there are probably a billion (or slightly less) examples of using keywords like:

(select 'user.name...

or:

(select :user name)

Or whatever.  Not good enough for me. I am more demanding.

So the first stab was something simple;  Just take an arbitrarily (I actually spelled that correctly the first time) long list of names, and create a string from it. And here it was:

(defmacro select (&rest args)
  `(mapcar #'write-to-string (list ,@args)))

Basically, take the parameter “args”, strip the () surrounding it, create a new list, and create a string from every member. A quick macroexpand show the outcome:

(macroexpand-1 '(select 'test 'me)) 
  -> (MAPCAR #'WRITE-TO-STRING (LIST 'TEST 'ME)) 
    -> ("TEST" "ME")

As shown, that is just a list of “test” and “me”. Doesn’t make the cut, mostly because I had to use “APOSTROPHEtest” instead of just “test”. Oh and there’s no string. Time to take care of that:

(defmacro select (&rest args)
  `(concatenate 'string  ,@(mapcar #'write-to-string args)))

So now it should take the list of strings ‘(“TEST” “ME”)’, and make it a nice string. DOES IT?!?!?

(macroexpand-1 '(select 'test 'me))
  -> (CONCATENATE 'STRING "'TEST" "'ME")
    -> OOPS

Go figure, it left the APOSTROPHE on the words. Actually, this is good sign. It means I don need to prefix the names with an APOSTROPHE  anymore. Next attempt:

(macroexpand-1 '(select test me))
  -> (CONCATENATE 'STRING "TEST" "ME")
    -> "TESTME"

Now it’s getting there. Only thing is: There needs to be a separation added. Duh, right? Might as well throw in the “SELECT” part too.

(defmacro select (&rest args)
  `(concatenate 'string "SELECT "
     ,@(mapcar #'(lambda (z) (concatenate 'string (write-to-string z) ", ")) args)))

Big change here was adding the “, ” to the converted keywords, then take the newly created partial string and make one long string.

(macroexpand-1 '(select user.name age))
  -> (CONCATENATE 'STRING "SELECT " "USER.NAME, " "AGE, ")
    -> "SELECT USER.NAME, AGE, "

And there it is. Can’t get much better than that.

Common Lisp and Reader Macros… You Better Sit Down For This

Fair warning: I only learned about reader macros today, so my terminology may suck. Well, most likely it would still even if I had a couple weeks. So it will suck more. Say, 20% more suck.

In case you didn’t get a chance to read my primer on macros (Let’s be honest, you didn’t. It’s ok, I’ll be fine.), this next macro may not look familiar. This is the post of which I type. A quick recap is that the macro would take this:

  (?> (+ 1% 2% 3%) '(4) '(5) '(6))

And create this code:

  (MAPCAR #'(LAMBDA (1% 2% 3%) (+ 1% 2% 3%)) '(4) '(5) '(6))

Essentially it took the original expression, and created a lambda with dynamically created parameters. (The 1% 2% 3% part) The macro “keyword” if you will is the “?>
Here’s the macro minus the helper methods. (The whole thing is the last section of the same post from above.)

  (defmacro ?> (conversion &rest args)
   `(mapcar #'(lambda (,@(create-placeholders args)) (,@conversion)) ,@args))

Now that’s pretty cool and all, but it still has to follow the general rule of Common Lisp: Every statement is encased in parenthesis. After all, the macro starts with “(?>”. What if there was a way to take that and remove any need for outer parenthesis? Turns out there is, and the term is “reader macros”. What’s the big difference between the two types? Glad you asked. Would have been a long, uncomfortable pause if you hadn’t.

Unlike normal macros that are expanded AFTER post read. That is, taking what is on the text file (.lisp file), and converting it to be compiled. So basically, read is pre-compile time. Why does this matter? Because you can instruct the reader on how to “digest” stuff from the .lisp file, and then prepare it for compile time. So like a normal macro that tells the compiler how to expand itself to compile ready lisp code, a reader macro tells the reader how to transform the text into useful pre-compile code. And yes, a reader macro can create a normal macro. In fact, that’s what this example will show.

Ok, so back to the normal macro above; It still has the normal {} encasing. What if I wanted to encase it with something else? Say something like #| |.

 #| (+ 1% 2% 3%) '(4) '(5) '(6) | 

Normally this would cause all sorts of problems, a linguistic middle finger if you will. Don’t worry, lisp won’t get away with that.

(set-macro-character #\| (get-macro-character #\)))
(set-dispatch-macro-character #\# #\|
  #'(lambda (stream char1 char2)
      (let ((pair (read-delimited-list #\| stream t)))
        (cons (read-from-string "?>") pair))))

So as far as I understand it, somewhere there is a table of symbols that are reserved by Common Lisp. For instance, the right parenthesis or ). The “set-macro-character” basically allows the addition of new symbols like ]. It is telling the reader that ] is ).

Next part is the actual macro. If you take away the #\ characters from “#\# #\|” you’re left with “#|“. This is what the reader will look for in order to read the code that follows the “#|“. Essentially this has set up the ability for the reader to take in “#| |” without throwing an error. The in between is what the rest of the code handles.

For whatever reason (Again I’m new to this) the “set-dispatch-macro-character” needs a method that takes in three parameters: “stream” “char1” “char2”, the significance for this I have yet to see. However, the “stream” parameter is important to this macro. The stream is the code that is read in after the reader finds “#|“. The needed code is the start of the stream until it hits “|”. In this example that would be:

  (+ 1% 2% 3%) '(4) '(5) '(6)

To match the original macro, there still needs to be the leading “?>”:

  (?> (+ 1% 2% 3%) '(4) '(5) '(6))

And that’s where the “cons” comes in. I simply appended “?>” to the read in code “(+ 1% 2% 3%) ‘(4) ‘(5) ‘(6)” to give me:

  (?> (+ 1% 2% 3%) '(4) '(5) '(6))

Which is exactly the code I needed to call the original non-reader macro. So not only was it possible to completely ignore lisp syntax, it was also possible to nest a normal macro within the reader macro.

 #| (+ 1% 2% 3%) '(4) '(5) '(6) |
    -> (?> (+ 1% 2% 3%) '(4) '(5) '(6))
      -> (MAPCAR #'(LAMBDA (1% 2% 3%) (+ 1% 2% 3%)) '(4) '(5) '(6))
        -> 15

Euler 3 Just Got Lisped Up

“What is the largest prime factor of the number 600851475143?”

One thing I’ve learned so far from the euler stuff is that if seems too hard, I’m doin’ it rong. What I initially did is go from 2, tried to find any prime number that is a factor 60085…3, and keep updating the highest found. This was silly. In reality, I needed to start from 60085…3, find the largest factor of it, and keep going if it’s not a prime number. After all, the highest possible factor can’t be higher than 60095..3/2, prime or not. If that fails, then increase the divisor by one, and check if the other number is a prime.

600851475143 / n = x where n 2 -> ?
600851475143 / 2 = x
600851475143 / 3 = x
600851475143 / 4 = x

This meant I needed two parts, one to roll through all possible values of n until x was a prime.

(defun lowest-prime-divisor (start &optional (current 2))
  (if (and (= 0 (mod start current)) (is-prime-number (/ start current)))
    (/ start current)
    (lowest-prime-divisor start (+ current 1))))

As I wrote before, this is taking the original number (6800??adf…3), and start with dividing it by 2. What ever the remainder is, take it and check if it’s a prime. If so, return that. If not, divide by 3. I have no clue why I named it lowest-prime-number. Probably a case where my limitless intellect is proving that I am not nearly smart enough to understand it.

Here is the brute force prime number check. Essentially start a 2, use mod, and increase the iteration. This is done until either something mod iteration is 0, or the iteration is the same as the number being checked. It has a special kind of ugliness, and inefficiency.

(defun is-prime-number (start &optional (currentDivisor 2))
  (if (= start currentDivisor)
      T
      (if (= 0 (mod start currentDivisor))
          nil
          (is-prime-number start (+ currentDivisor 1)))))

And I don’t have a macro this time. Mostly because I’m on 8 currently, and this is only the third post.