Tags related to tag palm
Tuesday, April 26. 2005
Delishious Pluckin Experiment
Del.icio.us is... well... delicious. It is an awesome method to store and organize your bookmarks. Here is one of the many reasons why. I have been marking certain links as "pluckme" for a little while now. What is this "pluckme"? It is just a short-hand way of saying "Download these web-pages into my PDA for further reading". Now, with Sunrise desktop (the software that talks to plucker) , you can view RSS feeds (An RSS fee is a 'stock-ticker' of information, links in this case). The final piece of the puzzle is the Del.icio.us RSS feeds. I am sure you can put it all together.
If I find a link I like, I just tell delish that I want to pluck it by giving it a 'pluckme' tag along with a special sub tag 'pluckme:1deep' or 'pluckme:2deep'. With Sunrise desktop, I subscribe to my pluckme:1deep RSS feed, and set it to download links 1 deep. The Same goes for pluckme:2deep. Bam. Instant plucky goodness. I am going to look into finding a better plucker->RSS app, because sunrise desktop, while good, is going to be turning commercial soon.
If I find a link I like, I just tell delish that I want to pluck it by giving it a 'pluckme' tag along with a special sub tag 'pluckme:1deep' or 'pluckme:2deep'. With Sunrise desktop, I subscribe to my pluckme:1deep RSS feed, and set it to download links 1 deep. The Same goes for pluckme:2deep. Bam. Instant plucky goodness. I am going to look into finding a better plucker->RSS app, because sunrise desktop, while good, is going to be turning commercial soon.
Wednesday, March 16. 2005
Language of the Year ... Pascal?!?
In "The Pragmatic Programmer", the authors suggest learning a new programming language every year. This year I have started to learn Pascal. No, not Delphi, but full on, old-school, pascal.
Now the major motivation here is that there is an awesome compiler and IDE for PalmOS, called PPCompiler. I am starting to reach the boundaries of what I can do with LispMe, so I figured I would jump into a compiled language, that was a little closer to the metal. (great saying when refering to a Tungstun E).
Besides a little bit of C to hack and slash a Litestep module, this is the first real lower-level language I have ever really played with. No virtual machines, no scripting, just compile and run baybee.
I am pleasantly surprised at how easy it is to pick up. Maybe I will build my own DA sometime.
Now the major motivation here is that there is an awesome compiler and IDE for PalmOS, called PPCompiler. I am starting to reach the boundaries of what I can do with LispMe, so I figured I would jump into a compiled language, that was a little closer to the metal. (great saying when refering to a Tungstun E).
Besides a little bit of C to hack and slash a Litestep module, this is the first real lower-level language I have ever really played with. No virtual machines, no scripting, just compile and run baybee.
I am pleasantly surprised at how easy it is to pick up. Maybe I will build my own DA sometime.
Monday, December 6. 2004
One macro makes you small... Scheme and the BunnyObject System
Awhile Ago I wrote about taking a jump down the scheme rabbit hole, and I got into the possibilities of building a type system on top of scheme, to illustrate the point that scheme looks more like building (domain specific) languages to solve your problem, rather then trying to retrofit a general language into your problem.
One of the things that scheme doesn't have natively (at least, not defined by R5RS) is the notion of classes and objects. It does have closures, and practically anything you can do with objects, you can do with closures (including building a class system, but I am getting ahead of myself). In fact, Scheme was built with the intention to play with an Actors Model style of OOP, and the original designers found that the special language constructs they built to create actors, and handle messages, can be adequately expressed with a lambda and case statement. You can see an example of this here: simple-object at the CSW.
So this time around (If you haven't guessed yet) I am going to show you the basics of building an object system within scheme. There are plenty of them out there and each one with their own properties. The one I am going to present to you is based around a simple closure-based object system, with a Meta-Object-Protocol. Because my Scheme-of-choice is LispMe, it makes use of "def-macro" style macros. If your scheme doesn't have this, you're going to have to convert it to your implementations method of macros (which is quite likely a hygienic macro. Go you.)
A Macro in LispMe takes one argument, a list of all the arguments passed to that macro with the car of that list being the name of the macro. This allows us to handle syntax inside of our macro. Very primitive mind you! This is the "Ugh Fire!", bone tools, and cave paintings of defining syntax.
Now, when I am defining my macro, I define a very simple stub macro, that calls a function, with the rest of the arguments passed to the macro, ignoring the first argument (that being the name of the macro). The primary reason I do this is that LispMe doesn't have any kind of native Macro-Expansion facilities, so this fudges a first-level expansion. This is by far the easiest way to debug a macro as well. Now, our macro will need to spit out a s-expression that will become our valid Scheme code. So we need to think about what we what to input (a list of member/method names) and what we want to output (a lambda-in-a-lambda closure, with a message handler of sorts).
Really, the most important thing is how we actually intend to use this class system. So, lets start by defining a class with our fictitious class macro:
You'll notice in this example I called the constructor %construct. This is similar to the PHP/Python method of naming important (or magic) members with a typographic convention (__, double underscore in PHP/python). I chose the scheme sigil %, which means "lower-level".
Another thing to note is that not only are these classes data structures first-class (that is, you can pass a class as an argument to a function or special form) but they are anonymous, just like lambdas. For instance, we could easily do something like this:
Of course, once we have this basis, we will find that it would be nice to have a way to tell if a slot was bound or not, (for our %act method), so we have '%in-slots?'. Because we are going to provide an intercessory MOP, we need a way to directly access and change slots, which we will call %get and '%set!' respectively. This will allow our class user to change the way a class works by using '%set!'. For instance, a very simple method of superclassing can be added by an object user by modifying %act to pass messages on to a parent class (or classes if you like). You could also institute private/public access control, aspect weaving, or practically anything else. The only thing that you cannot do is dynamically add members. This actually fits in (in my opinion) with how scheme itself works in regards to lexical scope.
All of the magick % slots can be over-ridden as well. For the most part, users of this class system will be most concerned with overriding %construct. %construct must be a procedure.
One you have a class, you can construct objects like this (using the point example):
As we saw in my other blog post, it is not difficult to build type systems in scheme, and in this one, it is not difficult to build object systems. The melding of the two (type and object systems) seems very natural to some, and is left as an exercise to the reader.
The possibilities of this object system however are pretty wide open. I have a working theory that an open-ended scheme-like object system with first class entities and a MOP would make expressing patterns (as in Gang of Four Design Patterns) extremely easily, clearly, and with brevity.
One of the things that scheme doesn't have natively (at least, not defined by R5RS) is the notion of classes and objects. It does have closures, and practically anything you can do with objects, you can do with closures (including building a class system, but I am getting ahead of myself). In fact, Scheme was built with the intention to play with an Actors Model style of OOP, and the original designers found that the special language constructs they built to create actors, and handle messages, can be adequately expressed with a lambda and case statement. You can see an example of this here: simple-object at the CSW.
So this time around (If you haven't guessed yet) I am going to show you the basics of building an object system within scheme. There are plenty of them out there and each one with their own properties. The one I am going to present to you is based around a simple closure-based object system, with a Meta-Object-Protocol. Because my Scheme-of-choice is LispMe, it makes use of "def-macro" style macros. If your scheme doesn't have this, you're going to have to convert it to your implementations method of macros (which is quite likely a hygienic macro. Go you.)
Design Decisions
The basics of the class construction are very similar to the simple object above. That is, we are going to use closures and message passing. except we are going to sugar out a lot of the extra syntax. The reason I chose this method is that I want each of the objects methods to have access to its fields in its environment. We're also going to keep a list of fields (and field values) available to the object so that we can provide a meta-object protocol.A little Digression on LispMe Macros
Given that the first element in the list that is the arguments to a LispMe macro is the name of the macro, it is not entirely inconceivable to build some kind of macro-dispatch system. You could do some kind of Aspect-Oriented-Meta-Programming with this. You could even build some kind of twisted class system out of this.LispMe Macros
LispMe macros are a bit weird. Sometimes I have found that if you use a macro on the same memo that you define it, LispMe will get all mention-not-use on you, and complain that [macro] is not a function. I don't know why that is, and I haven't really attempted to suss it out (or post a bug report, bad Jonnay!) but there it is. It also explains the list bound to default-slots, instead of a metaclass. Again, I get ahead of myself.A Macro in LispMe takes one argument, a list of all the arguments passed to that macro with the car of that list being the name of the macro. This allows us to handle syntax inside of our macro. Very primitive mind you! This is the "Ugh Fire!", bone tools, and cave paintings of defining syntax.
Now, when I am defining my macro, I define a very simple stub macro, that calls a function, with the rest of the arguments passed to the macro, ignoring the first argument (that being the name of the macro). The primary reason I do this is that LispMe doesn't have any kind of native Macro-Expansion facilities, so this fudges a first-level expansion. This is by far the easiest way to debug a macro as well. Now, our macro will need to spit out a s-expression that will become our valid Scheme code. So we need to think about what we what to input (a list of member/method names) and what we want to output (a lambda-in-a-lambda closure, with a message handler of sorts).
Really, the most important thing is how we actually intend to use this class system. So, lets start by defining a class with our fictitious class macro:
(define point (class
(slots (
(x 0)
(y 0)
(%construct (lambda (cx cy)
(set! x cx)(set! y cy)))
(get (lambda () (cons x y)))
(set-x (lambda (v) (set! x v)))
(set-y (lambda (v) (set! y v)))))))You can already see a few features of this class system by this very contrived example, First of all, class members (such as x and y) are visible to other members from within the class. This removes the need for an object to constantly call itself to get its own values. No more this.foo or $this->foo! Horray! (Though, as we shall see later, as part of the MOP, we are going to provide this kind of functionality.) Second of all, class methods are just members that happen to be lambda expressions, if you are a scheme programmer, this shouldn't surprise you. You'll notice in this example I called the constructor %construct. This is similar to the PHP/Python method of naming important (or magic) members with a typographic convention (__, double underscore in PHP/python). I chose the scheme sigil %, which means "lower-level".
Another thing to note is that not only are these classes data structures first-class (that is, you can pass a class as an argument to a function or special form) but they are anonymous, just like lambdas. For instance, we could easily do something like this:
((class (slots ( (foo 'baz) (%construct (lambda (f) (set-foo f))) (set-foo (lambda (f) (set! foo f))) (get (lambda () (list 'foo 'is foo)))))) 'bar)Which, constructs an object (with the argument 'bar) out of an anonymous class with the members foo, set-foo and get.
Liber MMM - Magickal Mystery Methods
%construct is one of them, but what kind, and how many other of these mystery methods should we have? The answer is actually quite simple. We're going to need one to handle the message, which we will call %act (after the Actors Model). We're also going to need a list of slots (or members) for this object, which we will call %slots, and a method to return that list, %get-slots.Of course, once we have this basis, we will find that it would be nice to have a way to tell if a slot was bound or not, (for our %act method), so we have '%in-slots?'. Because we are going to provide an intercessory MOP, we need a way to directly access and change slots, which we will call %get and '%set!' respectively. This will allow our class user to change the way a class works by using '%set!'. For instance, a very simple method of superclassing can be added by an object user by modifying %act to pass messages on to a parent class (or classes if you like). You could also institute private/public access control, aspect weaving, or practically anything else. The only thing that you cannot do is dynamically add members. This actually fits in (in my opinion) with how scheme itself works in regards to lexical scope.
And now... The Code
Now that we have our features all worked out, I am going to show you the code. It shouldn't be too hard to figure out.; Base.BunnyObjects
;; The actual macro. Note that it just calls %class
(macro (class a)
(apply %class (cdr a)))
;; This performs the work of writing out the class definition.
;; note that you can call it directly, and it will return the
;; sexpression, instead of constructing the class.
(define (%class . a)
; This is where we handle our syntax. 'a' is a list of
; our arguments, which start out being (slots (...))
; very similar to a let expression. Later I will add
; a (static (...)) syntax, and maybe a (parent (...))
; syntax.
;
; a-val is defined later. It simply applies a function
; to the value of an assoc.
(let ((slots (a-val cadr 'slots a)))
; Take the list of defined slots, and join it together
; with a list of the default slots. (see below)
;
; we do a set! here, because I am going
; to modify this soon to allow for inheritance
; alist-merge is defined later. It merges two
; associative lists, with the first taking
; precedence over the second.
(set! slots
(alist-merge slots
default-slots))
; Now we actually write out our first lambda, which will
; construct our closure-object
`(lambda c-args
; Write out our slot key-vals into a letrec.
(letrec ,slots
; Now we set our magickal member %slots to that
; key-val list for our MOP. We include both keys
; and values, so that we can add implementation
; inheritance later.
(set! %slots ',slots)
; Now we actually execute the classes constructor
(apply %construct c-args)
; And finally, return a procedure which will handle
; the message. Note that LispMe doesn't like
; dotted lists in a quasi-quoted expression , so I
; had to Unquote and requote instead.
,'(lambda (msg . margs)
(%act msg margs))))))
;; This is our list of default slots. The adventuresome user
;; could redefine this, and completely change the behavior
;; of all future objects at the time of redefinition.
(define default-slots
; Default constructor is empty.
'((%construct (lambda () ()))
; This handles messages.
; A message is generally (but not always) the quoted
; name of a procedure, and any arguments passed to it.
; every slot that is a procedure is a message. Note
; that we have to use EVAL to change the symbol (mention)
; to our identifier (use).
(%act (lambda (m a)
(if (and (%in-slots? m)
(procedure? (eval m)))
(apply (eval m) a)
(%no-msg m a))))
(%slots '())
(%get-slots (lambda () %slots))
(%in-slots? (lambda (slot)
(assoc slot %slots)))
; Again, we use eval
(%get (lambda (s)
(if (%in-slots? s)
(eval (list s))
(%no-slot s))))
; Again, we use eval.
; Note that this has a bug. It should also update the
; %slots. This is relatively minor at the moment, because
; the values of %slots isn't being used for anything... yet.
(%set! (lambda (s v)
(if (%in-slots? s)
(eval `(set! ,s v))
(%no-slot s))))
(%no-msg (lambda (m a)
(error (string-append
"no message ["
(object->string m)
"] with args: "
(object->string a)
" slots avail:"
(object->string %slots)))))
(%no-slot (lambda (s)
(error (string-append
"no slot: "
(object->string s)))))))
;; A simple, but useful procedure to mangle the result
;; of an assoc. for instance:
;; (a-val cadr 'foo '((foo bar)(baz blarg))) => bar
;; (a-val cdr 'baz '((foo bar)(baz blarg))) => (blarg)
(define (a-val p k l )
(if (assoc k l) (p (assoc k l)) #f))
;; Merges a primary alist list with a secondary list. As you might expect
;; If a member is in both lists, the primary member will take precedence.
;; The values of each alist are ignored.
;; It does no consistency checking. Bad Jonnay!
(define (alist-merge p s)
(cond ((or (null? s) (not s)) p)
((or (null? p) (not p)) s)
((assoc (caar s) p)
(alist-merge p (cdr s)))
(else
(alist-merge
(append p (list (car s)))
(cdr s)))))Now that we have Mentioned the BunnyObject System...
Lets actually use the thing. You define a class like this:(define point (class
(slots (
(x 0)
(y 0)
(%construct (lambda (cx cy)
(set! x cx)(set! y cy)))
(get (lambda () (cons x y)))
(set-x (lambda (v) (set! x v)))
(set-y (lambda (v) (set! y v)))))))The class macro returns a procedure that constructs objects specified by the arguments that you passed to class. The standard way to do this is to bind that procedure to a name. Like in the point class above.All of the magick % slots can be over-ridden as well. For the most part, users of this class system will be most concerned with overriding %construct. %construct must be a procedure.
One you have a class, you can construct objects like this (using the point example):
(define p1 (point 5 3)). Easy, no? Using the objects is a bit of a stretch for some OO guys, because we are not calling methods but passing messages. Remember that (with an un-modified object) every procedure is considered a message. So to use the methods in our point object :
(p1 'get) => (5 . 3) (p1 'set-x 2) => #unspecified (p1 'get) => (2 . 3) (p1 '%get-slots) => ((x 0) (y 0) (%construct ...) ... ) (p1 '%construct 3 2) => #unspecified (p1 'get) => (3 . 2)Note the passing of the %get-slots message. this shows the basics of the MOP. Also note that we can pass a '%construct message, which would re-initialize the object, in so far as it was initialized by it's constructor.
Conclusion?
As we saw in my other blog post, it is not difficult to build type systems in scheme, and in this one, it is not difficult to build object systems. The melding of the two (type and object systems) seems very natural to some, and is left as an exercise to the reader.
The possibilities of this object system however are pretty wide open. I have a working theory that an open-ended scheme-like object system with first class entities and a MOP would make expressing patterns (as in Gang of Four Design Patterns) extremely easily, clearly, and with brevity.
Listening to:
Rakimou - Plaid (6:01)
Wednesday, August 11. 2004
Day in the life...
Perhaps you've noticed the insane amounts of scheme in my blog recently. This is due to the ammount of attention units that I have in my life for ... well ... stuff.
Assume that anywhere between 4-10 hours a day (avarage about 8) are spent at work, doing things that are, or at the very least, resemble, "work". Assume that on those days, there are 2 hours of wind up, and 2 hours of wind down time. (showering, eating, relaxing, checking mail, getting to-from work, etc.). I need 8 hours of sleep a day. If I don't get 8 hours, assume that any time I gained due to lost sleep, I loose, due to lesser productivify. So that is 16-22 hours of my day accounted for.
I need at least 1 hour of social interaction between my wife and my daughter to stay sane. That is, if I don't have one hour, my sanity goes into the negatives. Ideally, It is closer to 2 or 3. Assuming on long work days, I spend less time with my family, and on shorter days, more time, that gives us an extra ammount of time at 1-5 hours. (or 19-23 hours spent).
Dinner takes around an hour. (obviously much less if I am eating a sammich. More if I am involved in the preperation and/or cleaning). 20-24 hours spent.
That leaves about 0-4 hours of time, per workday, on any of the multitude of my projects. Assume that most of my days are 8 hour days, and I am unwilling to give up time with my family (a reasonable assumption). That leaves me with about 2 hours of time. Knock off at least an hour of "puttering around". That is, incremental things like cleaning, fixing, pooing, and daily upkeep of self, family and house.
Knock off Another hour for meaningful external social interaction. That is, upkeep of friendships (this being purely upkeep)...
As you can see, I have no time for blogging. (and my life looks strangely like a game of the sims now) My blog cycle looks alot like this:
So there is an extremely small sub-set of things that I blog about, and a miniscule ammount of time to blog it in. Usually it has to do with either A) my current obsession, and or B) whatever I was reading/playing with on the bus. usually that means LispMe, the portable scheme interpreter, or The Structure and Interpretation of Computer Programs.
There is my monthly metapost.
Assume that anywhere between 4-10 hours a day (avarage about 8) are spent at work, doing things that are, or at the very least, resemble, "work". Assume that on those days, there are 2 hours of wind up, and 2 hours of wind down time. (showering, eating, relaxing, checking mail, getting to-from work, etc.). I need 8 hours of sleep a day. If I don't get 8 hours, assume that any time I gained due to lost sleep, I loose, due to lesser productivify. So that is 16-22 hours of my day accounted for.
I need at least 1 hour of social interaction between my wife and my daughter to stay sane. That is, if I don't have one hour, my sanity goes into the negatives. Ideally, It is closer to 2 or 3. Assuming on long work days, I spend less time with my family, and on shorter days, more time, that gives us an extra ammount of time at 1-5 hours. (or 19-23 hours spent).
Dinner takes around an hour. (obviously much less if I am eating a sammich. More if I am involved in the preperation and/or cleaning). 20-24 hours spent.
That leaves about 0-4 hours of time, per workday, on any of the multitude of my projects. Assume that most of my days are 8 hour days, and I am unwilling to give up time with my family (a reasonable assumption). That leaves me with about 2 hours of time. Knock off at least an hour of "puttering around". That is, incremental things like cleaning, fixing, pooing, and daily upkeep of self, family and house.
Knock off Another hour for meaningful external social interaction. That is, upkeep of friendships (this being purely upkeep)...
As you can see, I have no time for blogging. (and my life looks strangely like a game of the sims now) My blog cycle looks alot like this:
- Media injection while waking up (news, blogs, wikis, etc.) and on the way to work (yay plucker!)
- Get to work, and spend 10-15 mins spewing into w.blogger.
- If spew is good, post.
- Post again during lunch, if I have relevent thoughts
- Depression - (Blog entries about how depressed one is, is so freakin lame. I used to hang out with a bunch of StrongSads. They were, and are still, very sad people.)
- Guilt - sometimes i spiral into wells of guilt. I don't feel like talking, much less posting a (semi)perminant record of that.
- Privacy - sometimes I just dont want to wear my life on my sleve.
- Anger - only posted in anger once or twice. In most cases I regret it.
- Exaust - Life is hard sometimes. You don't wanna hear about it, and I don't wanna post it.
So there is an extremely small sub-set of things that I blog about, and a miniscule ammount of time to blog it in. Usually it has to do with either A) my current obsession, and or B) whatever I was reading/playing with on the bus. usually that means LispMe, the portable scheme interpreter, or The Structure and Interpretation of Computer Programs.
There is my monthly metapost.
Monday, August 2. 2004
Palm Digitizer Loop
With older palm pilots, you can get caught up in what is commonly referred to as a "Digitizer Loop". This is really annoying if you happen to need to do a Hard Reset (because of lost battery power and sketchy caps, for instance), and you're stuck, in palm setup mode, because of the stupid digitizer that will not go away.
An interweb search will reveal mostly fruitless results. Vague suggestions to try various free and shareware digitizers that get caught up in the same loop, or worse yet, torrid tales of returns, return returns and rereturn returns of various palm mXXX handhelds.
Eek.
Funnily enough however, the solution is really simple.
Just do a soft reset that bypasses the startup. Just hold down the up button while hitting reset at the back of your device. Bam. No more digitizer loop. Of course, if you happen to hit the digitizer preference...
An interweb search will reveal mostly fruitless results. Vague suggestions to try various free and shareware digitizers that get caught up in the same loop, or worse yet, torrid tales of returns, return returns and rereturn returns of various palm mXXX handhelds.
Eek.
Funnily enough however, the solution is really simple.
Just do a soft reset that bypasses the startup. Just hold down the up button while hitting reset at the back of your device. Bam. No more digitizer loop. Of course, if you happen to hit the digitizer preference...
Friday, July 16. 2004
Baby Steps with call/cc
So I have been playing around with Scheme recently. More specifically, LispMe An R5RS version of scheme available for PalmOS.
Scheme has this interesting language element called call-with-current-continuation or call/cc. I am only just starting to learn about it, what it is, and what it does. My initial impression is that call/cc is a higher-order goto. You invoke call/cc with a function that takes one argument, that argument is the "continuation". A simple example is this: (call/cc (lambda(q) q)), So the anonymous function takes one argument, (the continuation) and returns it. So what you end up with is this magickal continuation object. The groovy thing is that you can use that continuation object as a function, and it will jump back to where it was defined.
The best thing I can do at this point is give you an example. Here are two functions, (fall) and (fly). They are very similar. fall makes a boid (if you don't know what a boid is, it is a sim-bird. Think New York: "Hey boid, shaddap!" ) fall to the ground, while fly makes the boid fly. I use call/cc here to defy gravity.
For those that don't know LispMe, move is a function that takes 2 arguments, an x and y, that move the pen to the location. set-pattern sets the pattern of the brush (#t for black, #f for clear) rect is a function that draws a rectangle, its arguments are the the x and y of its end-point, and the radius of the corner. (the start point being the current pen position.)
So here it is:
The most important thing about continuations is that a continuation isn't just an address to a location in code (like a goto), but that it is a first class object that has a representation of the state of the program. (Or at least, in my limited understanding!). Just like in the old days, programmers used GOTO and JMP to emulate the behavior of the higher-level control structures we use now (while, until, break, continue, etc.) call/cc lets us do the same for things like exceptions, transactions, etc. The groovy thing is that while in the old days, GOTO's couldn't be effectively reused. (A goto was always a goto, even when you were using it as a break) The higher-level control structures that are offered by call/cc can be generalized. You can write a generalized exception handler or coroutine builder just once, and not have to worry about call/cc and just try, catch, and coroutine till the cows come home.
The coolest part of the whole thing is that it gives you the opportunity to build your own higher level control structures. Who knows what is out there?
Update: Thanks to jemfinch and chandler for setting me straight. (call/cc (lambda(q) q)) is not the way most people use call/cc.
Scheme has this interesting language element called call-with-current-continuation or call/cc. I am only just starting to learn about it, what it is, and what it does. My initial impression is that call/cc is a higher-order goto. You invoke call/cc with a function that takes one argument, that argument is the "continuation". A simple example is this: (call/cc (lambda(q) q)), So the anonymous function takes one argument, (the continuation) and returns it. So what you end up with is this magickal continuation object. The groovy thing is that you can use that continuation object as a function, and it will jump back to where it was defined.
The best thing I can do at this point is give you an example. Here are two functions, (fall) and (fly). They are very similar. fall makes a boid (if you don't know what a boid is, it is a sim-bird. Think New York: "Hey boid, shaddap!" ) fall to the ground, while fly makes the boid fly. I use call/cc here to defy gravity.
For those that don't know LispMe, move is a function that takes 2 arguments, an x and y, that move the pen to the location. set-pattern sets the pattern of the brush (#t for black, #f for clear) rect is a function that draws a rectangle, its arguments are the the x and y of its end-point, and the radius of the corner. (the start point being the current pen position.)
So here it is:
; call-cc sample
(define (fall)
(let ((x 0) (y 30))
(while (or (< y 160) (< x 160)) ;-- while were
(wait 10)
(draw-boid x y #f)
(set! x (+ x 1))
(draw-boid x y #t)
; gravity... It's the law!
(draw-boid x y #f)
(set! y (+ y 1))
(draw-boid x y #t)
)))
(define (fly)
(let ((x 0) (y 30) (c #f))
(while (or (< y 160) (< x 160))
(set! c (call/cc (lambda (q) q)))
(wait 10)
(draw-boid x y #f)
(set! x (+ x 1))
(draw-boid x y #t)
(c c) ;-- This calls the continuation c,
; effectively jumping to just before the call to (wait 10)
; fuck you gravity!
(draw-boid x y #f) ; these functions
(set! y (+ y 1)) ; are never
(draw-boid x y #t) ; executed
)))
(define (draw-boid x y p)
(set-pattern p)
(move x y)
(rect (+ x 10) (+ y 10) 0))
Now, really, I am not doing anything exciting here, I am just using call/cc as a jump here (as a continue statement actually). So if you don't know what call/cc is, then you are probably wondering "what the hell? how is that different from a goto?" Well, really, that would take more explanation on what a continuation actually is, and how it works in the context of call/cc. (Better Men Than I have done it).The most important thing about continuations is that a continuation isn't just an address to a location in code (like a goto), but that it is a first class object that has a representation of the state of the program. (Or at least, in my limited understanding!). Just like in the old days, programmers used GOTO and JMP to emulate the behavior of the higher-level control structures we use now (while, until, break, continue, etc.) call/cc lets us do the same for things like exceptions, transactions, etc. The groovy thing is that while in the old days, GOTO's couldn't be effectively reused. (A goto was always a goto, even when you were using it as a break) The higher-level control structures that are offered by call/cc can be generalized. You can write a generalized exception handler or coroutine builder just once, and not have to worry about call/cc and just try, catch, and coroutine till the cows come home.
The coolest part of the whole thing is that it gives you the opportunity to build your own higher level control structures. Who knows what is out there?
Update: Thanks to jemfinch and chandler for setting me straight. (call/cc (lambda(q) q)) is not the way most people use call/cc.
Listening to:
Kiss FM Breakbeat Show - (01-1 - Tom Middleton (1:55:00)
Kiss FM Breakbeat Show
Sunday, May 30. 2004
Plucker Desktop Hangs on Startup
So, I've been using this great little app for my Palm Pilot, called Plucker. It is a (relatively) thin HTML document reader. It is MOUNDS better then avant go, easier to use, and doesn't require the use of a third party server. On top of that, it is GPL. (horray!)
The problem is, the Desktop component (which lets you download, and convert HTML documents + Images into something Plucker can read) will sometimes crash, and crash hard. Maybe it complains about the "Locale '(gibberish)' can not be set"
The fix? First off, try moving the plucker.ini out of the way. That should fix the problem. If you want to keep the channels that you set up earlier, just Copy them over one by one. They are all at the bottom of the file, and true to ini file format, each channel name (and configuration section) is in [square brackets]. You can try and copy over the whole lot of em, but if that doesn't work, (and you start crashing again) remove each channel one by one till you have it working.
For the record, plucker totally kicks the tits out of Acrobat Reader.
The problem is, the Desktop component (which lets you download, and convert HTML documents + Images into something Plucker can read) will sometimes crash, and crash hard. Maybe it complains about the "Locale '(gibberish)' can not be set"
The fix? First off, try moving the plucker.ini out of the way. That should fix the problem. If you want to keep the channels that you set up earlier, just Copy them over one by one. They are all at the bottom of the file, and true to ini file format, each channel name (and configuration section) is in [square brackets]. You can try and copy over the whole lot of em, but if that doesn't work, (and you start crashing again) remove each channel one by one till you have it working.
For the record, plucker totally kicks the tits out of Acrobat Reader.
(Page 1 of 2, totaling 8 entries)
» next page




