Anonymous callbacks
Anonymous callbacks
Is there a way to pass a lambda as a callback to a guiserver element without assigning it to a symbol?
Quick answer: No.
But perhaps you can play some tricks understanding the following:
You can pass either a symbol or a string, but the string must not contain any spaces. So guiserver parses it one as one token (see the definition of gs:button in guiserver.lsp. So this would both work:
guiserver parses out the the action token with a simple Java SringTokenizer. So it will break up the string along spaces. This is what guiserver does when formatting the event:
Then gs:listen in guiserver.lsp just das a eval-string on the string received.
But most important, what are your trying to do? Why not assgining the lambda function to a symbol?
Lutz
But perhaps you can play some tricks understanding the following:
You can pass either a symbol or a string, but the string must not contain any spaces. So guiserver parses it one as one token (see the definition of gs:button in guiserver.lsp. So this would both work:
Code: Select all
(gs:button "TheButton" 'myaction "press me")
(gs:button "TheButton "MAIN:myaction" "press me")
Code: Select all
String action = params.nextToken();
...
guiserver.out.println("("+ action + " \"" + id + "\")");
But most important, what are your trying to do? Why not assgining the lambda function to a symbol?
Lutz
There are always other ways to accomplish it. But one of the most useful, er, uses of an anonymous function is to define simple callbacks.
That's what makes Javascript so usable as a gui framework, and practically the entire basis of libs like Prototype.
I suppose I could create a wrapper macro that would handle things for me, assigning incremental symbols, but that would be a work-around (because it would not be an anonymous function anymore).
By allowing anonymous functions as callbacks, you free up the library considerably. You can store an entire menu system in a table that can be quickly and easily edited. It would allow a handy recursive macro that could create the menu system from the table at runtime.
That would allow programs that are easily extensible by the user; provide an interface to the table and we have a program that is extensible in newLisp a la emacs.
I really think this is something that is worth considering as a change to the way the guiserver works, although I certainly understand the practical constraints of writing a parser in Java (blech).
That's what makes Javascript so usable as a gui framework, and practically the entire basis of libs like Prototype.
I suppose I could create a wrapper macro that would handle things for me, assigning incremental symbols, but that would be a work-around (because it would not be an anonymous function anymore).
By allowing anonymous functions as callbacks, you free up the library considerably. You can store an entire menu system in a table that can be quickly and easily edited. It would allow a handy recursive macro that could create the menu system from the table at runtime.
That would allow programs that are easily extensible by the user; provide an interface to the table and we have a program that is extensible in newLisp a la emacs.
I really think this is something that is worth considering as a change to the way the guiserver works, although I certainly understand the practical constraints of writing a parser in Java (blech).
Also, a note on how lambdas make interface programming more elegant. You do not clutter up the name space and it is much easier to follow a chain of functions when they are defined within their parents. It also makes large chains of callbacks easier, and is more idiomatic of a lisp.
Here is an example: button A creates dialog B with button C on it. When button A is pressed, it calls a function that generates dialog B with button C. Where is the action of button C defined? If it is unique, there is no reason not to use an anonymous function.
In addition, isn't it more elegant for button A to actually create dialog B and button C, rather than just making those elements visible?
Here is an example: button A creates dialog B with button C on it. When button A is pressed, it calls a function that generates dialog B with button C. Where is the action of button C defined? If it is unique, there is no reason not to use an anonymous function.
In addition, isn't it more elegant for button A to actually create dialog B and button C, rather than just making those elements visible?
It is only the communications link needing the action as a compact token. Yoy could easilyt reqite the gs:button and gs:listen functions.
... passed into the new definition of gs:button.
On the gs:listen side you get back a base64 encode sitting right after the parenthesis containing the text of the lambda expression. Use a regex replace on the event string to transform:
Lutz
Code: Select all
(gs:button 'TheButton (lambda (x) (println (upper-case x)) "press-me")
Code: Select all
(define (button id action text)
(net-send out (string "button " " id " " (base64-enc (string action)) " " (base64 text) "\n")))
Code: Select all
; event received in gs:listen
event => (KGZvbyAoeCkgKHByaW50bG4gKHVwcGUtcmNhc2UgeCkpKQ== "TheButton")
; into
event => ((foo (x) (println (upper-case x))) "TheButton")
Lutz
One could add a second gs:listen-apply and gs:check-event-apply in the file guiserver.lsp.
the classic gs:listen would do:
the gs:listen-apply would do:
All incoming events are of the form:
so the regular expression would change this to:
I can put it on my list for later (still churning out basics as fast as I can ;-) )
Lutz
the classic gs:listen would do:
Code: Select all
(eval-string event)
Code: Select all
(set 'event (replace xxxxxx event yyyy 0))
(eval-string event)
Code: Select all
"(<action> <p1> <p2> ....)"
Code: Select all
"(apply '<action> '(<p1> <p2> ...))"
Lutz