Friday, November 11, 2011

False Alarm. Also, Teensy

It turns out that I jumped the gun putting up that dragon emblem[1], so you won't be rid of me as soon as I was expecting. I did end up putting some hours into the PostScript generator port over to Common Lisp (and it looks about as good so far, though I still need to get my head firmly around dictionaries), but I also had to get something to play around with this weekend, in the absence of any Nords.

Actually, now that I think about it, I'm not sure I ever mentioned my dalliance with embedded programming. In an effort to add a capitol C logo to the header there, and to have some fun with low-level electronics, I bought up an Arduino Uno a while ago[2]. This is probably going to incinerate what little programmer cred I have, but I couldn't for the life of me get the damn IDE to actually upload a program to the chip. This was a while too; the board has been sitting there disused, still retaining the default blink program it was shipped with. I've looked at various potential fixes including getting a more recent version from the repos, downloading the official tarballs from the Arduino site, and toying with some command line utilities to program the thing without that fucking annoying little collection of big shiny icons. I officially give up. That removable Atmega328 may get re-purposed at some point, but I'm not sinking another hour into figuring out exactly why the programming tools don't seem to recognize the board.

There's a point to all this, I swear.

I mentioned that I wanted something else to keep me busy through the weekend[3], so I ended up hitting up my local electronics store for a Teensy 2.0. The funny part, to me at least, is that the little packing slip that came with this chip states

Programming Teensy with C provides access to all features. Experience with the C language and reading technical specifications is helpful. For a beginner oriented environment, [the] Arduino may be a better choice.

The reason that's slightly amusing is that, as I mentioned, the Arduino constantly drove me to frustration. By contrast, I got the Teensy up and running in under ten minutes by following the Getting Started tutorial. It boils down to

  • Install the required libraries (apt-get install gcc-avr binutils-avr avr-libc libusb-dev)
  • Download the loader program (either the binary version for your architecture, or the source. Remember to run make if you go with the source version.)
  • Plug in the Teensy
  • Press the pushbutton to activate the HalfKay loader
  • Load your code onto it (either by running the GUI, or by using ./teensy_loader_cli -mmcu=[your processor here] -wv program.hex)

That's that.

I haven't actually started anything yet, but I plan to go through the listings of a few projects to warm up, hopefully culminating in a build of a Chordite and addition of a new logo in a little while.


Footnotes

1 - [back] - Canada Post cheekily celebrates Remembrance Day, so I'll actually have to wait until Tuesday or so to actually get my hands on my RPG fix for the year.

2 - [back] - The old one with the removable Atmega chip, rather than the new one with the tiny but soldered unit.

3 - [back] - As if I didn't already have enough projects in the air.

Thursday, November 10, 2011

PostScript and Temporary Goodbye

So I honestly thought I'd be talking about Erlang and various processing tactics relating to it. I was also potentially planning to do and talk about some more work on clomments, the main off-hours project I've been trying to keep at. As an absolute last resort, I was going to dive into some more Elisp, or maybe finally talk about the shell-ui project. It didn't occur to me that the week would see me dusting off an old implementation of postscript for some new code.

I haven't actually written new code for it, but I have gone over what was there and flipped through the few resources I could find. Postscript, the language, is actually more versatile than I gave it credit for the last time around. To the point that I might actually want to revisit postscript.plt as opposed to just porting what I had over to CL.

Going through the first of the resources I mention above, it actually occurred to me that I could likely accomplish some of my goals by typing .ps directly. I'm going to try that first, but still keep the embedding option in my back pocket to hedge against some issues. First impressions are that the stack is going to annoy the ever-loving fuck out of me. I remember trying out Forth a while ago and not really minding that aspect of it[1], but I honestly can't see how to write a procedure that takes more than two or three parameters without doing some serious head-scratching. If you want the argument order to be at all sensible, it seems like you need to chain exch, dup and pop like a fiend, with an index or two thrown in for good measure. That means functional programming in this language is at least slightly hobbled from the get-go, but it does force you to make the smallest possible procedure to avoid being shot in the foot inadvertently.

The other reason that implementing PostScript in another language would probably be a good idea is, ironically, performance. Not writing performance, obviously, but processing performance at the printer end. If you take a look at that third resource I link to and open it in your editor of choice, you'll notice that the author deliberately chooses one and two letter identifiers for their procedures.

Ordinarily, I'd agree that that's awful, but keep in mind that every extra character in an identifier is one more that the printer will have to parse before outputting. Shortcutting grestore to gr or lineto to li doesn't seem like much, but compounded by the number of invocations per page, pages per document copy and then by copies per hour, I could see that getting scary pretty fast where frequent output is concerned. Now, that's really not much of a reason for me to actually apply this directly; I'd much rather write with human-readable function names and have an intermediate machine compress them down to a more compact format before sitting it in front of the printer. That's basically what I see using the lisp-based generator for; if I plan it out properly, the result will be a much easier language to work in that actually has more efficient output than a hand tuned chunklet of PS.

I was going to promise to post more related content soon, but frankly, as you can see from the new addition to the language bar, you aren't likely to see me for a month or so.


Footnotes

1 - [back] - Maybe it had some syntactic help; I no longer remember, never having done any serious development in it.

Friday, November 4, 2011

Objective Lisp

Stand back! I have dramatic pause an idea!

(defpackage :objective-lisp
    (:nicknames :ol)
    (:use :cl)
  (:shadow #:+ #:- #:* #:/ 
           #:member #:null
           #:= #:string= #:eq #:eql #:equal #:equalp
           #:length #:map #:mapcar #:concatenate)
  (:export #:+ #:- #:* #:/ 
           #:member #:null
           #:= #:string= #:eq #:eql #:equal #:equalp
           #:length #:map #:mapcar #:concatenate))
(in-package :objective-lisp)

;;; not, strictly speaking, relevant to what I want to discuss,
;;; but I figure I've already gone off the deep end just by
;;; writing this, so I may as well make it worth my while

(defun nullp (object) (cl:null object))

;;; or is it...
(defun memberp (item list &key key)
  (cl:member item list :key key :test #'=))

;; imagine other functions here

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defmethod + ((num number) &rest nums)
  (assert (every #'cl:numberp nums))
  (apply cl:+ (cons num nums)))

(defmethod - ((num number) &rest nums)
  (assert (every #'cl:numberp nums))
  (apply cl:- (cons num nums)))

(defmethod * ((num number) &rest nums)
  (assert (every #'cl:numberp nums))
  (apply cl:* (cons num nums)))

(defmethod / ((num number) &rest nums)
  (assert (every #'cl:numberp nums))
  (apply cl:/ (cons num nums)))

(defmethod length (seq) (cl:length seq))

(defmethod map ((fn function) (l list) &rest lists)
  (assert (every #'listp lists))
  (apply #'cl:mapcar fn (cons l lists)))

;; and defined for other types here

(defmethod concatenate ((str string) &rest strings)
  (assert (every #'stringp strings))
  (apply #'cl:concatenate 'string (cons str strings)))

;; and again

(defmethod = (a b) nil)
(defmethod = ((a number) (b number)) (cl:= a b))
(defmethod = ((a string) (b string)) (cl:string= a b))
(defmethod = ((a character) (b character)) (cl:char= a b))
(defmethod = ((a symbol) (b symbol)) (cl:eq a b))
(defmethod = ((a cons) (b cons)) (cl:equalp a b))
(defmethod = ((a array) (b array)) (cl:equalp a b))
(defmethod = ((a structure-object) (b structure-object)) (cl:equalp a b))

;;; really, I should do the same for all the various
;;; comparison functions (>, >=, <=, <), but this is
;;; already longer than I'd like

Now, why would we want to do this terrible thing? Well, we probably wouldn't. I wouldn't ever straight-facedly recommend someone does this in any sort of production environment, but it does sand down some rather annoying corners[1].

What looking at CLOS this way gets you is the easing of a few syntactic binds at the cost of some performance.

  • For starters, we now have a generic = that can be called in pretty-much any situation[2]. That lets us define memberp and other functions without having to pass in a test function (= handles dispatch itself). It also lets us define map/concatenate and similar functions without specifying what the output type is expected to be[3].
  • As I note, it saves us from having a separate =, char= and string= and similar comparison operations.
  • Finally, if we define new types (such as matrix), we are not prevented from giving them a + or * method (and we can specifically define how to go about mapping, concatenateing or lengthing them, if it makes sense, as well as defining the correct new equality test without having to name it matrix=).

You could also do things like override + so that it performs concatenation for strings[4], though I'd shrink from going further and applying it to sequences in general, just because it's somewhat ambiguous.

Because all these calls are handled by the type system, you'd also get compile-time warnings about operations that aren't defined.

Incidentally, I know I'm not even remotely the first person to think of doing something like this on a lark. As usual, I just wanted to get an idea far enough out of my head to take a good look at it.

This has been a completely random thought about Lisp. Thank you for your time.


Footnotes

1 - [back] - In case you care, I stubbed my metaphorical toe on them a little while ago by trying to implement matrix operations in CL as a learning exercise only to find that I couldn't actually give them a + operation. It would have to be something like add or matrix-add. No world-ending obstruction, but slightly less than satisfying. At the time I implemented it as matrix-add.

2 - [back] - leaving aside the identity vs. pointer question that may actually need to be addressed differently in some cases

3 - [back] - Although, to be fair, we do lose the ability to do something like (concatenate 'string "Hello " (list #\t #\h #\e #\r #\e #\!))

4 - [back] - Since that seems to be well accepted in most languages by this point.