Wednesday, March 21, 2007

Tour of Qi 7.2 and 6.2 diff

Since my computer is still not back up to speed after my crash (I was making backups during the crash. Praise be the Gods of Irony, I hath mended my ways. Smite me no more!), I thought I'd take a quick tour over the differences between Qi 6.2 and 7.2. So fire up your diff browser and join along on this magical ride in CodeLand!

And like any good tour, it starts off with a mystery!

Why on earth is it named Qi 7.2!? I could see going from 6.2 to 7.0 as it now runs on a new Lisp compiler and has some added language features. But I can see no real reason to name it Qi 7.2 other than Mark COULD name it Qi 7.2. Anyway, like any good tour, we now will move on without actually solving the mystery.

Right away, we find the new definition of "no waffle" for the CMUCL compiler. We also come across a great comment quote:

\No waffle from the CMU or CLisp compiler. Speed max, safety min because Qi has a type checker.\

I like telling the compiler, "Speed Max, Safety Min! because I know better than you!" Of course, Qi has to do a lot of work to "know better" than the compiler, but it's every programmers dream to tell the compiler "full optimization, I've got this nailed!"

From here, we find some code to handle the different types of closures on CMU, namely the INTERPRETED-FUNCTION type. It almost makes me want to stop and dig into the difference between FUNCTION and EVAL::INTERPRETED-FUNCTION, but this is a tour so we have to get moving.

(DEFUN fix-closures ()
#-(OR CLISP CMU) (ERROR "Qi does not recognise this platform ~A" (LISP-IMPLEMENTATION-TYPE)))

Our next bit of action is when we find the brand new curry rules for tuples. If you have noticed, some of my posts contain monster tuples with so many @p's that your eyes almost bleed. Now Qi will turn (@p name x_loc y_loc) into (@p name (@p x_loc y_loc)) for me! I'm already dreaming of the @p's I get to kill with this feature. We would go hunting for them... but it is a .... we'll YOU know.

The system function table lets us know that we should expect 2 new system functions, mlet and new-assoc-type. Like a sign in an amusement park, it entices with future happiness. And then, in a moment, it has passed by.

(define compile_to_machine_code
Name Rules -> (do (PUSHNEW Name (value *userdefs*))
(put-prop Name lambda (compile_to_lambda
(compile_to_lambda+ Name Rules))))))

Now we come along and find that compile_to_machine_code stores the name of our function along with a "lambda" property that it keeps the lambda compilation in. It isn't something that you would often think about, but if you end up using property lists with the same name as functions in your code, you would want to know about this.

\Make association between Qi type and Lisp type.\
(DEFUN new-assoc-type (X Y) (PUSHNEW (LIST X Y) *assoctypes*) 'associated)

And now we come along to something dangerous and FUN! A play with at your peril type of function. You can now create your own match between a Qi type to a Lisp type. Originally, the assoc list only contained things like numbers, strings, symbols, but now you can add your own. Obviously, use this at your own peril as the typechecker will believe anything you tell it. I believe there may be an article on using that in a pathological manner and seeing what happens. But our boat flows on...

\Params [F X] -> (lisp_code Params [apply F (lisp_code Params X)]) where (element? F Params) \

\Above changed in 7.1\

Params [F X] -> [apply F (lisp_code [F | Params] X)] where (element? F Params)

Here we find that the function call now does not recursively lisp_code on the applied function anymore. This won't change the meaning of the code but perhaps it produces faster code on CMU? Perhaps compiling the apply doesn't matter as the params are already taken care of in X? Tour guides often speculate wildly on their subject matter. I choose not to break with that tradition here.

\Translate mlet into let. Works for dotted pairs.\
(define expand-mlet
[@p W X Y | Z] -> (expand-mlet [@p W [@p X Y | Z]])
[mlet V W X Y | Z] -> (expand-mlet [let V W [mlet X Y | Z]])
[mlet X Y Z] -> (expand-mlet [let X Y Z])
[X | Y] -> (map-dotted-pair expand-mlet [X | Y])
X -> X)

Yet another gem in 7.2! This will really save on the number of parens in my code. You can now (mlet X 2 Y 3 (+ X Y)) to get 5! The only think I need to implement now is a lambda that does pretty much the same thing. I.e. (/. [ X Y ] (+ X Y)) converts to 2 lambdas in the correct order. You'd think you could do this with a Macro, but you would be wrong. /. is a special form, not to be messed with in any macro. I've tried!

After some boring CMU details that I'll skip over, we find that the typechecker now calls curry_type in a few more places, presumably to handle the new tuple action, but maybe its just for more complete typing in general. But let us not dally, we are nearly finished!

And like any good tour, some couple breaks up during it sending us out with a zoom!

\Modified in 7.1 to allow stops to be embedded in alphanums.\
\I gave up on Qi-YACC! \

(define process-prolog-chars

Apparently, poor Qi Yacc didn't want to parse the input properly. But do not worry, she's still around. And perhaps even she can be cajoled into parsing things correctly with some fancy trickery not yet invented by the human mind. Who knows, it even could be YOOOOUUU!

Please exit the boat carefully and I hope you have enjoyed this Diff Tour of Qi 6.2 and Qi 7.2. We will return to your irregularly scheduled coding posts after a nice clean OS install.