Re: ClassField and Chart
Thanks Alex, its working. Its been quite a learning experience. regs Konrad On Sat, Mar 10, 2012 at 7:20 PM, Alexander Burger a...@software-lab.de wrote: Hi Konrad, The code is still crashing and it has something to do with how I'm using the class field. OK, I found two more errors: 1. The chart's put function should not set the class field to 'This' (list This (: nm) (diestr (: level)) (: notes)) but to the object's type (i.e. th list of classes) (list (type This) (: nm) (diestr (: level)) (: notes)) 2. Then, the return value of the get function is wrong. It returns the 'Data' list (the visual representation): (put! Itm 'notes (cadddr Data)) Data ) ((car Data) It must be the object 'Itm' in the current row (put! Itm 'notes (cadddr Data)) Itm ) ((car Data) With that, we have: (gui '(+Set +E/R +Chart) '((L) (filter bool L)) '(gear : home obj) 5 '((Itm) (with Itm (list (type This) (: nm) (diestr (: level)) (: notes)) ) ) '((Data Itm) (cond (Itm (put! Itm 'nm (cadr Data)) (put! Itm 'level (caddr Data)) (put! Itm 'notes (cadddr Data)) Itm ) ((car Data) (new! (car Data) 'nm (cadr Data) 'level (diestr (caddr Data)) 'notes (cadddr Data) ) ) ) ) ) (table NIL NIL '((NIL Type) (NIL Name) (NIL Level) (NIL Notes)) (do 3 (row NIL (gui 1 '(+ClassField) '(curr) '((Armour +Armour +Item) (Weapon +Weapon +Item) (Item +Item)) ) (gui 2 '(+TextField) 10) (gui 3 '(+TextField) 4) (gui 4 '(+TextField) 30) (gui 5 '(+DelRowButton)) ) ) ) (scroll 3 T) Cheers, - Alex -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe -- read my mind at: http://the-willows.blogspot.com/ -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: ClassField and Chart
Hi Alex, I don't actually understand the choMaster function or why I would actually need one? the model I have is: (class +Monster ...) (rel gear (+List +Joint) whos (+Item)) (class +Monster ...) (rel whos (+Joint) gear (+Monster)) And I'm trying to add the list of Gear objects onto the Monster page. So the master is always going to be the object in (: home obj). Do I just wrap that up as an anonymous function? regs Konrad. On Thu, Mar 8, 2012 at 6:39 PM, Alexander Burger a...@software-lab.de wrote: On Thu, Mar 08, 2012 at 08:24:02AM +0100, Alexander Burger wrote: (gui '(+E/R +Chart) '(children : home obj) 5 '((This) (list NIL This (: nm))) car ) (table NIL NIL '(NIL (NIL Class) (NIL Name)) (do 6 (row NIL (gui 1 '(+ChoButton) '(choMaster (field 1))) (gui 2 '(+ClassField) '(curr) '((Armour +Armour +Item) (Weapon +Weapon +Item )) ) (gui 3 '(+TextField)) (gui 4 '(+DelRowButton)) (gui 5 '(+BubbleButton)) ) ) (scroll 6 T) Obvoiusly, '(: nm)' in the chart's get function should be '(: name)'. Then, if you want the name to be editable in the chart, you can change the above to ... (gui '(+E/R +Chart) '(children : home obj) 5 '((This) (list NIL This This)) car ) ... '((Armour +Armour +Item) (Weapon +Weapon +Item )) ) (gui 3 '(+Obj +TextField) '(name +Master) 30) (gui 4 '(+DelRowButton)) ... That is, you pass the object 'This' instead of just the name '(: name)' to the chart field, and make the field an '+Obj' field (holding an object instead of just plain text). Cheers, - Alex -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe -- read my mind at: http://the-willows.blogspot.com/ -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: Structuring a GUI project to avoid stop - starts
Thanks Jose, If I'm understanding this correctly the simple way to do this is to put the logic for each page in its own file. so instead of (de report ..) I would have a report.l file that just contains the guts of what I'm coding. Reloading model.l is not really an issue for me. Besides at the moment if it does change ir porably means that the underlying database also needs to be nerfed and recreated becasue I've made large changes to the the entity structures. THough this is not likely at this stage where I'm mostly working on getting my reporting function to spit out the HTML that I want. regs Konrad. 2012/3/6 José Romero jose.cyb...@gmail.com: Hi Konrad, On Tue, 6 Mar 2012 12:46:44 +1100 Konrad Zielinski kzielin...@gmail.com wrote: Hi, At the moment I have my project in two files model.l which contains my domain classes, database init code and other related functions. server.l which contains my URL handling functions. I find that I'm constantly having to kill and restart the server process and then navigate to the code I'm working on. This is quite cumbersome. Is there a way to get the running picolisp process to detect and action changed source files without constant restarts. regs Konrad You could just use the technique Alex uses, most of the code that may need some quick tweak for each object is contained in a file that is quickly 'loaded every time a request for that object arrives. If you are careful designing the application you could make server.l 'load model.l again once in a while (maybe by visiting some secret URL). if you have stuff in server.l that may change very often, move it out to another module. If you want to automatically detect a changed file and reload it, you could code something like this, on Linux, using inotifywait(1) (I use this code for synchronizing files between my shared host and my laptop over ssh+rsync) # Recursively watch the current directory (setq *InotifyFD (pipe (call 'inotifywait -mrq -e modify,create,move,delete . ) ) ) (de reload () # load modules, initialize variables, etc etc. ) (task *InotifyFD (in *InotifyFD # The process died somehow, clean up. (when (eof) (task *InotifyFD)) (line) # Eat notification. # Wait 5 secs for the notifications to settle before reloading
Re: How do Relations and gui objects hook together.
Hi Alex Thanks for the explanation. Though this really should be mentioned in the documentation. Its a rather obscure call in Family.l which just looks like its creating a Heading. but it turns out to be vital for the application to work. I notice that there are a few other methods defined in form.l that are not actually documented anywhere. The button helpers I can sort of work. But the choDlg and panel with their long and rather complicated argument lists are somewhat harder to puzzle out. regs Konrad On Thu, Feb 16, 2012 at 8:02 PM, Alexander Burger a...@software-lab.de wrote: Hi Konrad, I've being trying to work out how the Family.l application hooks together its database and gui objects together and simply haiing no luck. as far as I unsetad the current Person object is being stored in the global variable *ID by the (default *ID (val *DB)) call. *ID is used only temporarily, to communicate the object across HTTP calls as URL parameter. The real place of the object is normally in the 'obj' property of the form. The crucial call here is (id ...) 'id' takes care of storing the object in *ID into the 'obj' property of the current form, enable or disable the form according to certain rules, and lock the object if necessary. but then none of the gui calls seem to reference this object at all. So how is one hooked up to the other. There the crucial item is the +E/R prefix class (as you noticed). It takes care of connecting the displayed value in the GUI component to the internal DB object's attribute. Also what are the initilisation arguments to the +E/R prefix class They take the form of a cons pair, with the attribute (relation) in the CAR, and an executable expression giving the object in the CDR. Whenever +E/R needs to read a value from the object into the GUI, or write changes from the GUI to the object, it evaluates the 'exe' in the CDR to obtain the DB object. supposed to mean '(nm : home obj) . The first one appears to be relation name but what does the rest of the lsit do. I've tried So 'nm' is the relation (e.g. the person's name), and '(: home obj)' the object expression. As the object is stored in the 'obj' property of the current form, and each GUI component knows the form it resides in from its 'home' property, '(: home obj)' means: Get my (the GUI component's) home form, and from that the object. readin the code and the libraries it imports and re reading the Applicaton development document several times but it just seems to skip over this point. We have information on DB programming and The documentation is not (yet) complete here. It's really a lot of stuff, and explaining it all would probably be longer than the implementation itself. I hope this will improve in the future. Cheers, - Alex -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe -- read my mind at: http://the-willows.blogspot.com/ -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: android success with full picolisp
Do you know if this approach would work for on a Kindle Keyboard as well? It would be an interesting way to add functionaltiy to my kindle. regs Konrad On Tue, Feb 21, 2012 at 2:04 PM, Joe Bogner joebog...@gmail.com wrote: Doug - Neat! I took a different approach and got picolisp working on my android phone and kindle fire by using terminal-ide (http://code.google.com/p/terminal-ide/ ) as the shell and cross compiling picoLisp with gcc-arm-linux-gnueabi on my linux box. I can post the binary if anyone is interested. I didn't do anything with it because terminal-ide (and it's busybox compile) couldn't resolve DNS (didn't include a /etc/resolv.conf) and I lost root at the time with my kindle fire. http://forum.xda-developers.com/showthread.php?p=22103721 . I was originally going to play around with scripting out something that involved the network. I kicked around shelling out to a java app to resolve DNS but then moved onto another project. Other than that it worked great. It was nice to have VIM around as well. I may go back to it at some point but didn't really have a practical use for it on android especially since I could just ssh into my linux if I wanted to tinker with picoLisp. Thanks for sharing On Mon, Feb 20, 2012 at 9:46 PM, Doug Snead semaphore_2...@yahoo.com wrote: More android + picolisp fun, this time with the full picolisp. Using the android SDK and NDK, I hacked a picolisp/src/makefile to work for android's arm processor like this: --- makefile --- [snip] CFLAGS := -c -O2 -pipe \ -falign-functions=64 -fomit-frame-pointer -fno-strict-aliasing \ -W -Wimplicit -Wreturn-type -Wunused -Wformat \ -Wuninitialized -Wstrict-prototypes \ -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 # ?? had: -m32 NDK_ROOT = ~/android/android-ndk-r7 NDK_BIN = $(NDK_ROOT)/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin SYS_ROOT = $(NDK_ROOT)/platforms/android-8/arch-arm/ CC = $(NDK_BIN)/arm-linux-androideabi-gcc --sysroot=$(SYS_ROOT) LD = $(NDK_BIN)/arm-linux-androideabi-ld AR = $(NDK_BIN)/arm-linux-androideabi-ar RANLIB = $(NDK_BIN)/arm-linux-androideabi-ranlib STRIP = $(NDK_BIN)/arm-linux-androideabi-strip OS = Arm PICOLISP-FLAGS = -m32 -rdynamic LIB-FLAGS = -lc -lm -ldl DYNAMIC-LIB-FLAGS = -m32 -shared -export-dynamic [snip] - Then (to my surprise) picolisp and dynamic libraries were made, # file ../bin/picolisp ../lib/ext ../lib/ht ../lib/z3d ./bin/picolisp: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), stripped ./lib/ext: ELF 32-bit LSB shared object, ARM, version 1 (SYSV), stripped ./lib/ht: ELF 32-bit LSB shared object, ARM, version 1 (SYSV), stripped ./lib/z3d: ELF 32-bit LSB shared object, ARM, version 1 (SYSV), stripped So far so good... Using this android approach generally, http://gimite.net/en/index.php?Run%20native%20executable%20in%20Android%20App I placed the picolisp executable in the assets dir and at run-time, copy it from assets to /data/data/ in the right place for that app. Since I'm using the emulator and I know where the executable was placed, I can run it using adb, for some command-line tests: # adb shell /data/data/com.mytest/picolisp '-de foo (X) (println X)' '-foo 123' -bye 123 # adb shell /data/data/com.mytest/picolisp '-de foo (X) (println (* X 2))' '-foo 123' -bye 246 # adb shell /data/data/com.mytest/picolisp '-de foo (X) (println (* X 2))' '-foo 12345' -bye 24690 A bit cumbersome having to unpack the executable and other files from the app's .apk (zip archive) to run it ... but it can be done. And no fiddling with bits ... no changes to the (full picolisp) source at all. Next step is to try to similarly unpack all the libraries and see if a picolisp database server application can be run. Then more testing. And use that with android's browser, all within an android app. But I'm very confident that the full picolisp will run on the android from what I see so far! There are ways to call java from C also, so that opens up possibilities of using android java libraries from android picolisp too. Cheers, Doug -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subjectUnsubscribe -- read my mind at: http://the-willows.blogspot.com/ -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: Canonical way to do master detail relationship.
Thanks Alex, I Believe this is what I was looking for: (class +Master +Entity) (rel children (+List +Bag) ((+Key +String)) # description ((+Number)) ) # rank I'll see how I go with it. As to number of details I'm expecting it to sit at less then 5 almost all the time, with no detail records being the most common case. regards Konrad -- read my mind at: http://the-willows.blogspot.com/ -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
UNSUBSCRIBE
Good bye konrad Zielinski kzielin...@gmail.com :-( You are now unsubscribed -- read my mind at: http://the-willows.blogspot.com/ -- UNSUBSCRIBE: mailto:picol...@software-lab.de?subject=unsubscribe
Re: Status of 64 picoLisp
Hi All, It would appear that setting up a chroot is remarkably easy, well under debian anyway, I can't speak for other distros as I haven't tried. AndJus it seems to work quite nicely too, even if their are other ways to do it. Anyway now that I have a chroot I can install a version of Firefox with flash as well : ) Disclaimer: I have not examined the low level virtual machine to any level of detail. the following is a general observation about VM's. For all I know the people behind LLVM have done things better. Some languages are simply sufficiently different that they do not work well on some virtual machines. Attempting to implement Erlang on the JVM comes to mind. The underlying primities are different. Often what generic virtual machine means is good for any language sufficently close to C, IE staticly typed etc. Lisp is not decented from C and makes somwhat different assumptions about a lot of things, so it may not be a good fit. And now back to questions about 64 bit picolisp: Is switching to an assembler going to mean the demise of gcc.l ? Are we going to see inline picoLisp Assembler instead?O How is a new assembler based version of Picolisp going to affect 32 bit platforms. I imagine they are going to be arround for quite a number of decades yet? Regs Konrad On 16/10/2008, Tomas Hlavaty [EMAIL PROTECTED] wrote: Hi Alex, thanks for explanation. I was curious to try picolisp bignums and must say that for somebody doing anything serious, it is probably rather inefficient. As a benchmark, I tried the example from http://paste.lisp.org/display/15116 (setq X 0) (setq Y 1) (for (N 2 (= N 100) (inc N)) (let Z (+ X Y) (setq X Y) (setq Y Z))) (prinl Y) Very rough results using picolisp native bignums: (= N 1) $ time ~/picolisp/p gmp-test2.l -bye gmp-test2.log real 0m0.131s user 0m0.124s sys 0m0.008s (= N 10) $ time ~/picolisp/p gmp-test2.l -bye gmp-test2.log real 0m10.190s user 0m10.157s sys 0m0.008s (= N 100) $ time ~/picolisp/p gmp-test2.l -bye gmp-test2.log C-c C-cKilled real 17m58.856s user 17m51.687s sys 0m5.572s (killed after 18 mins!) The original C program: $ time ./gmp gmp.log real 0m50.060s user 0m50.059s sys 0m0.004s I wrote simple ffi wrapper for gmp library and the results: $ time ../../p gmp-test.l -bye gmp-test.log real 0m50.507s user 0m50.239s sys 0m0.248s using the following code: (setq X (mpz_new)) (setq Y (mpz_new)) (mpz_init X) (mpz_init Y) (mpz_set_ui X 0) (mpz_set_ui Y 1) (setq Z (mpz_new)) (for (N 2 (= N 100) (inc N)) (mpz_init Z) (mpz_add Z X Y) (mpz_set X Y) (mpz_set Y Z) (mpz_clear Z)) (mpz_print Y) (prinl) Would not it be better to use gmp library for bignums if they are going to be supported? What is the reason picolisp has bignums in the first place? Do you/somebody else use it for anything? Would not it be simpler and good enough on 64 bit systems not having them at all? What impact on interfacing foreign libraries the asm rewrite have? Cheers, Tomas -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED] -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED]
Re: Status of 64 picoLisp
I suspect this would be in contradiction to some of the stated goals of PicoLisp, For one you would no longer be close to the machine. Just close to the virtual machine. On 16/10/2008, Jakob [EMAIL PROTECTED] wrote: On 15 Oct 2008, at 9:11 AM, Alexander Burger wrote: It is a complete rewrite. Even the implementation language changed. Instead of C it is written in a generic assembler (which in turn is written in PicoLisp :) that generates GNU assembler code (currently there is only a x86-64 generator, but other CPUs are possible). Oh. Please consider http://en.wikipedia.org/wiki/Low_Level_Virtual_Machine Because it is awesome, and if you port to that, you do not have to port to any other architecture. I was only recently made aware of LLVM, and it is really cool. Apple reportedly has started using it, probably wise from their past experience with switching CPU architecture. With LLVM, switch as much as you like. And no, LLVM is NOT another Java in disguise. LLVM is like a real CPU. regards, Jakob -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED] -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED]
Re: Cutting a circular list.
2008/10/13 Tomas Hlavaty [EMAIL PROTECTED]: Hi Konrad, Well thats two improvements to the documentation. Perhaps a perfect candidate for the Wiki? Hmm. var - Variable: Either a symbol or a cell (set 'var 'any ..) - any Stores new values any in the var arguments. See also setq, val and def. Even taken in concert these two snippets don't actually explain what will happen if var is a cell. It may be obvious (if you already know) that if var is a cell than action will be taken on the car part. However it does not actually say so. I note that the definition of con does say so even though its signature has the more specific data type of Lst. The best a very careful first time reader could pick up is that the behavior is not explicitly spelled out. They could then, guess, experiment or ask. I would say that there are some functions where additional verbosity is warranted. the function for assigning values is one such place. Especially when the acutal behaviour may not be what people with Lisp experience expect. While succinctness is good in documentation, it is possible to have too much of a good thing. nothing is perfect but rather than arguing with Alex about quality of his documentation, would not it be easier and more useful to take action and put it in the picoWiki? I think everybody would appreciate your knowledge and it would be preserved for newcomers too. Yes I intend to. I'd like to give something a little more substantial on structure manipulation. There is a few things I have in mind. It would at least make it easier for Alex not to spend his lifetime maintaining his documentation to everybody's tastes and focus on his clients, writing code and having fun instead;-) Documentation is part of the reason why picolisp is a great project. There are too many Open source projects where the code is the documentation. As such improvements to the documentation are just as important as improvements to the code. As I said earlier this seems a point which is sufficently important to be in the core documentation. The one nice thing about having core documetnation, which is local to my system is that I can access it when I'm offline, which is most of the time. I get the impression that some people stay online constantly. Here in Australia however internet connections are comparable expensive (we don't have true unlimited usage plans, it is all metered by download amount). So my laptop stays offline unless I really, really, need somthing that isn't on my system. regs Konrad. There are many different Lisp dialects so people's expectations could vary depending on their background. A wiki page for people comming from Common Lisp background, for example, would be great! Cheers, Tomas -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED] -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED]
Re: picoWiki
Hi, After some consideration I agree that supplementing the core docs is better then replacing them. If I could make a feature suggestion. It would be handy if there was a shortcut syntax for linking to the definition of terms in the core documentation (much as the lisp tag currently does). so that we didn't have to type the entire address every time. possibly {ref set} to refer to the refS.html#set in the core documentation. regards Konrad. 2008/10/14 Tomas Hlavaty [EMAIL PROTECTED]: Hi Randall, In my experience, a Wiki is only truly successful if there are very clear rules, styles, and usually someone with a heavy hand to enforce that. Would you have any suggestions what those rules and styles should be? A simple solution would be, just duplicate the documentation in the I am not sure whether it is a good idea completely replacing the documentation Alex created and maintains. Alex will probably not give that up anyway? However, the existing documentation is a good start, e.g. http://logand.com/picoWiki/classes then can be filled with comments, examples, observations, ideas etc. like I started with http://logand.com/picoWiki/+Blob It would be good to address things that are not covered by his documentation, are out of scope for the core picolisp package, link to other people's blogs or software or elaborate where we feel more information is necessary for people not enough familiar with picolisp (like me;-). Alex's documentation can be incorporated in the forms of links like for example in the lisp markup and maybe integrated with the search function. Wiki, make it better and better and make sure it is well supported. This would be an ideal to aim for:-) Cheers, Tomas -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED] -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED]
Re: Cutting a circular list.
Hi Alex, Well thats two improvements to the documentation. The description of set says: Stores new values any in the var arguments. I suspect it should say what you said above. and have a see also link to con. regs Konrad. On 11/10/2008, Alexander Burger [EMAIL PROTECTED] wrote: Hi Konrad, (set 'A (1 2 3 4)) (set 'B (cdr A)) ... (set (cdr A) NIL) The 'set' function puts a value into the CAR part of a cell (no matter whether this is a list cell or a symbol). A B | | V V +-+-+ +-+-+ +-+-+ +-+-+ | 1 | ---+--- | 2 | ---+--- | 3 | / |--- | 4 | / | +-+-+ +-+-+ +-+-+ +-+-+ ^ | (cdr A) So 'set' receives the cell which is pointed to by 'B', and stores 'NIL' into its value cell. What you want to achieve is A B | | V V +-+-+ +-+-+ +-+-+ +-+-+ | 1 | / | | 2 | ---+--- | 3 | / |--- | 4 | / | +-+-+ +-+-+ +-+-+ +-+-+ i.e. storing NIL into the CDR part of the first cell of 'A'. 'set' cannot do this, but 'con' stores a value in the CDR part of a cell: : (con A NIL) - NIL : A - (1) : B - (2 3 4) the goal is to take a list build by fifo and turn it into a normal list starting at the 2nd element. so instead of (4 1 2 3 .) I get (1 2 3 4) You were on the right way: : A - (4 1 2 3 .) : (setq L (cdr A)) - (1 2 3 4 .) : (con A NIL) - NIL : L - (1 2 3 4) : A - (4) Cheers, - Alex -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED] -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED]
Re: picoWiki
Yes, Wiki's can be quite useful. Getting a copy of the standard reference documentation on there would be useful. Then we could all work on expanind it a little as the current desciptions are quite terse in places. Granted the fact that we have readable documentation at all is a great boon, and a credit to the author, way too many projects out there don't have docs worth spitting at, let alone reading. A Cookbook of how to solve various task would probably be the next step. At the moment my mode of operation seems to be: 1) try to do X 2) get stuck 3) Ask Alex 4) Get a response with code which is remarkably consise and uses functions I ether didn't know existed or had completly forgotten about. There seems to be a lot of cool and consise ways of doing things once you join the dots of which sets of functions to use together : ) I certainly would consult a wiki, and do my best to contribute where the occation arose. P.S. how did you do the syntax highligting for lisp code? It's a rather nice feature. regards Konrad. On 09/10/2008, Alexander Burger [EMAIL PROTECTED] wrote: Hi Tomas, class=i href=?ChangesChanges/a, w3m will interpret it as http://logand.com/?Changes. It works in Firefox though, i.e. it opens http://logand.com/picoWiki?Changes page as intended. Just tried with both w3m and firefox, and both seem to work well :-) Cheers, - Alex -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED] -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED]
Re: Asyncronous IO
Hi Alex, that sends me back to the drawing board a little. Yet again I recall seeing the fifo function but didn't realise I might need it : ) A few other things occured to me as I was working on this on the train. The task and *Run mechanism (if used with enough care) give us non blocking reads. But the underlying select function also provides non blocking writes. so that you can dely trying to write to a socket until it is ready for more data. It would appear that task and *Run have no way of using this part of the select function. There is also out of band data as a thrid set of descriptors however all the documentation suggests that this is rarely used unless you are doing particularly low level magic. regards Konrad. 2008/10/10 Alexander Burger [EMAIL PROTECTED]: Hi all, Sorry for the confusion, Let me try to explain the situation: In the present system, it does not help at all to put the socket into non-blocking mode. The reason is that select() is conceptionally separated from read(). After select() signals (correctly or incorrectly) that data are available, the corresponding task's body is executed. It will try to read from that socket, and from that moment there is no way back. When no data at all arrive, or only a few bytes but not the complete message, it has to wait until the full message is assembled, be it blocking or non-blocking. Even if select() would be accurate, and never send an event to the tasks unless there are really data available, it would not help because there might be less data available than are needed for the full message, and the missing data might never arrive. So if you need to do such things asynchronously, the whole process of assembling the message - probably byte by byte - has to be put into a separate task. And you need a timeout for that task, too, because it may well be that the message will never be completed. The timeout should abort that task and close the connection. In this case, a non-blocking mode might be helpful, as in cases where select() wrongly said that data are available will not block the system, but most probably in those cases the data will arrive a few milliseconds later anyway (when the TCP stack resends the packet), or the connection will close down (sending EOF to the task), and processing will resume. Only in the - very few - remaining cases, the timeout will fire and have to cleanup the task and its connection. The drawback of implementing such a fully non-blocking system will be that the present separation of event generation (select) and data processing (read) cannot be held up any longer, and a completely different application flow is required. Therefore, I would go with the current solution, collect the messages in the task's body character by character (or even byte by byte), and implement a decent timeout for the pathological cases where this message assembly gets stuck for whatever reason. The collection of those pieces in the background might be done nicely with the 'fifo' function, keeping a first-in, first-out list for each task, and some supervisor logic in a higher layer checks those queues for messages, and retrieves and executes them. Just my two yen. Cheers, - Alex -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED] -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED]
Re: Asyncronous IO
Ahh, I belive the issue is that I have actually installed picoLisp under usr/local but don't use it exclusivly from that directory. As such I get the following: script src=http://localhost:8080//usr/local/picoLisp/lib/form.js; type=text/javascript/script which includes an absolure path to forms.js regards Konrad On 08/10/2008, Alexander Burger [EMAIL PROTECTED] wrote: Hi Konrad, sufficently abstract the URL space from the physical disk. Most other mature frameworks allow your to creat a completly virtual url space which has no relation to physical files on disk. The way the forms.l maps a full path to its javascript file and puts it in the output Hmm, which path do you think of? There is only one .js file referenced in form.l, and it appears as src=http://localhost/8080/lib/form.js; makes me particularly uncomfortable as it is exposing data on where I have installed picolisp. so the only path that is exposed is lib/. Where do you see the installation path? In general, the GUI only uses relative paths anyway. (note: the /8080/ is not part of the path, but the port encoded for httpGate). Cheers, - Alex -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED] -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED]
Re: Asyncronous IO
Henrik, all of the references I'm aware of are based on Python. the standard Python library includes modules called asyncore and asynchat (sections 17.5 and 17.6 of the Python documentation. The original Asyncronous webserver (as far as I'm aware) is medusa http://www.nightmare.com/medusa/ http://www.amk.ca/python/code/medusa Twisted is a more mature (read complex) implementation of the same thing. At this stage i belive they have reimplemented everything and don't even use the standard asyncore module anymore. I use teisted at work and from the application developers point of view the system allows complex applications to be built in very neat small peices. The approach has the advantage of not having the same kind of concurrency issues as threaded code has. By definition asyncronous code is only doing one thing at a time, so there is no danger of two functions accessing the same data objects at the same time, without the need for stemapors or locks. I believe that the Erlang language uses a similer approach to implement its light weight processes, and it allows them to scale to thousands of processes. regards Konrad On 08/10/2008, Henrik Sarvell [EMAIL PROTECTED] wrote: Sounds clever, but very complicated maybe to maintain the scheduling? You mentioned multiplayer online games as a possibility, are the big ones with thousands of simultaneous users already operating under these principles? It would be great if you could point me to a resource on the basics behind this way of doing things. /Henrik -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED] -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED]
Re: Asyncronous IO
Hi All, In the matter of how to begin. Twisted is I think the wrong place. It is a very large and complicated beast which has grown in its own unquie direction. So much so that it is incompatable with a lot of standard python tools and libraries, uses its own logging system etc. In copying python the place to start are Asyncore and Asynchat. The Medusa pages had some basic examples of building an asyncronous client and then an asyncronous proxy. I intend to try to build these things and satisfy myself that I'm really getting asyncronous behaviour. After that I'm thinking that a good proof of concept application would be a basic instant messanger which allows multiple users to connect and send messages to each other. this is a nice application which has shared state without needing a particularly fancy interface. As this is a personal project, I'm happy to share code, questions and comments through this list if there is interest. A similer Tic Tac Toe server which allows multiple simultainous games and routes moves to the correct clients would also be nice. Then its on to the main event. where more care is needed in working out what functions are needed and how additional functionality should be hooked into the system. Here I would be aiming to build a generic UDP and TCP server that is as adaptable as Medusa and Twisted. At this point, if there is enough interest. putting code on Sourceforge or Google code might be worth while. Heck it might even give pico Lisp some extra publicity. (I note this list has been getting a little more lively lately, which is a good sign). And can be used as a base for any protocol anyone chooses to throw at it. One reason why the Async approach is well suited to python is due to limitations in the Python interpreter. Python has something called a Global interpreter lock, which restricts it to using a single CPU, even if threading primitives are used. Ergo threading primities become an overhead which increases code complexity without giving increased scalability. I believe that picoLisp has similer single CPU limitation, I'm pretty sure that there are no threading primitives. So the only possible choices are Asyncronous or Forking. The latter makes shared state somewhat difficult to manage, and exists allready (so there is nothing new to build). 2008/10/9 Alexander Burger [EMAIL PROTECTED]: Hi all, oops, sorry! Forget what I wrote: A .html file will be directly sent to the client, without any forking. And also .l files do not automatically cause the fork, but only if (app) is called during their execution. This was wrong. The 'server' function in lib/http.l will always fork when a connection request arrives. It is just that the child process immediately terminates after serving the connection (unless (app) was called). BTW, as a matter of an example, the 'server' function in lib/http.l *does* implement a non-forking server, but only in the child process once the initial connect from a client has created a session: ... (loop # Main loop in the parent process (setq *Sock (listen P))# Wait for a request (NIL (fork) (close P)) # The child closes 'P' and exits the loop (close *Sock) )# The parent closes the new connection and continues (task *Sock (http @)) # The child installs a task on that socket (http *Sock) # and serves the first page (or *SesId (bye)) # If (app) was not called, terminate (task *Sock # Else install a task for the new session socket (when (accept *Sock) # Accept requests on that socket (task @ (http @)) # without forking (http @) ) ) ) Note: This uses in two places a construct of the form (task socket (http socket)) (http socket) The reason for that is that for HTTP/1.1 more than one transaction may be done before the connection is closed. Hope this helps. Cheers, - Alex -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED] -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED]
Re: Asyncronous IO
Hi Alex, your response to Tomas's questions dosn't seem to have made it to the list. Most of the documentation I have seen seems to suggest that Sockets need to be put into non blocking mode explicitly, ie using select() is not sufficent. At a low level attempting to read from a nonblocking socket will return a Would Block error condition. Is the picoLisp socket and task code allready setting sockets into non blocking mode? regards Konrad. 2008/10/9 Tomas Hlavaty [EMAIL PROTECTED]: Hi Alex, thanks for the explanation! Tomas -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED] -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED]
Re: Asyncronous IO
Hi Henrik the whole idea of an asycronous server is that you only use one process. to handle all requests. this way session data can be stored without using an external symbols. Even further several clients may share state in some way, though the only example I can think of off the top of my head is a multiplayer online game. The performance asumption is that your server is I/O bound and not cpu bound. Generally anytime you do something that may block you need to differ that processing probably by adding the waiting resource as its own task. And in the meantime move on to other processing such as other waiting requests. The only time I would spawn a new process is if a request needed somthing very intensive done. We would then need to have a task waiting on the other process to complete its work. the idea is that your process is not allowed to block, so each time IO is needed the currently executing code needs to be suspened, so that the system can do something else without blocking. Twisted dose this by breaking up larger lgoical units into small functions that essentially sechdule a handler function to be handled when an external resoult is ready as the last thing before returning. I am operating at the limits of my understanding here and to be honest I'm not certain how the whole differed processing model will translate into picolisp. Though on the face of it, I think it should transfer rather well. The Task mechanism along with some other functions I reacal reading about seem up to the job. regards Konrad. 2008/10/8 Henrik Sarvell [EMAIL PROTECTED]: Konrad, I'm also a fan of friendly urls and the way you describe it is currently how I have set things up to work with Apache through custom logic in PHP and mod_rewrite. Let me know if you want any help and I'll try my best :-) I don't know exactly what you're aiming at and I couldn't get a lot of details from the Twisted homepage. What I would like though is a restful setup similar to Apache + PHP. All state/session information would then be stored in the Pico DB and accessed through a unique session id, just like in PHP. Each time a request happens a new pico process is spawned and whatever is designated to happen happens and finally the pico process terminates. In effect each script would be its own little mini-application. This model is arguably the main reason why PHP dominates web development at the moment, that and the fact that it's a templating language automatically. Automatic templating is something I can live without though :-) /Henrik -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED] -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED]
Re: using the http server to return xml
I think my problem with setting mime types originally was due to basing my code on the initial hello world example, where the html function is called bare inside project.l. In this model the call to server is on the command line. I'm guessing this means that Mime remains whatever it was when server started and my setting of mime was taking place in a forked process for the request, and hence was not actually affecting anything. I am guessing here as I havn't read the http code in detail yet. Now that I'm doing somthing similer to the sample application and having a app.l which does all the loading and calls server from inside picoLisp code I suspect things will work correctly. I still don't quite follow what curl is supposed to be showing is wrong with my use of http header. I'm installing it now and will dig further. I'm determined to get this thing working right. On 04/10/2008, Alexander Burger [EMAIL PROTECTED] wrote: Hi Konrad, I've got it returning an actual .xml file ok. (had to modify the definition of *Mimes directly as calling (mime xml text/xml 1) didn't seem to have any effect. Though this is not central to your question, it is strange because it should work. Where in your code did you call 'mime'? Should be ok anytime after lib/http.l is loaded. Cheers, - Alex -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED] -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED]
Re: using the http server to return xml
Thanks Alex, the following fixed the problem. As the bulk of my app will be sending xml files arround like this I guess I can make these settings globally for the application. I'm not entierly sure what the implications are. but I suspect their not too important providing my documents don't grow to some ridiculous size. regards Konrad. On 04/10/2008, Alexander Burger [EMAIL PROTECTED] wrote: On Fri, Oct 03, 2008 at 09:32:43PM +1000, konrad Zielinski wrote: (de mydata2 () (httpHead text/xml; charset=utf-8 1) (xml? T) (xml '(root NIL Document 2)) ) mydata works perfectly. mydata2 fails to roduce any output. Now the Not sure what the problem is, but two things come to mind: 1. In which context is 'mydata2' called? If the connection is not closed for some reason, you could try to call (flush) after sending the data. 2. If the initial request from the browser was HTTP/1.1, then the global '*Http1' is set to '1', causing the picoLisp server to initiate a chunked transfer. You could try (let (*Http1 0 *Chunked NIL) (httpHead text/xml; charset=utf-8 1) ) Cheers, - Alex -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED] -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED]
Re: Contriving a static variable.
Thanks Alex, now that I know the solution the entry for job in the reference manual makes perfect sense. {reviously I couldn't quite work out how it differed from bind. Pico Lisp does seem to be a rather challenging language to learn, getting to a point of know what builtin to use when. Especially if you have been away from any lisp programming for a while (as I have). However I'm determined to master it so bear with my and the questions should get a little more insightfull. regards Konrad 2008/6/13 Alexander Burger [EMAIL PROTECTED]: On Fri, Jun 13, 2008 at 01:14:04PM +1000, konrad Zielinski wrote: I've been trying to get my head around how closures work in Pico lisp. As PicoLisp uses dynamic binding, there are no _direct_ static lexical clausures. As in other cases too, the programmer has to (or better: can) control things directly. There are several functions to control dynamic environments, like 'bind' or 'job'. specifically how would I set up a variable a function which returns successive integers each time it is called. I would use 'job' here (de counter () (job '((Cnt . 0)) (inc 'Cnt) ) ) You supply a list of variables (here 'Cnt') and initial values (here '0') to 'job', and a runtime body. : (counter) - 1 : (counter) - 2 If you inspect this function : (pp 'counter) (de counter NIL (job '((Cnt . 2)) (inc 'Cnt)) ) You see that the explicit environment is maintained by 'job'. During the execution of the runtime body (inc 'Cnt), the variables are dynamically bound to their values, and saved thereafter. My first Idea was to return this form anther function but it didn't work You can this, too. The 'curry' function employs 'job' in certain cases (de make-counter (InitialValue @Increment) (curry (@Increment InitialValue) () (inc 'InitialValue @Increment) ) ) Calling 'make-counter' returns a new function : (make-counter 0 1) - (NIL (job '((InitialValue . 0)) (inc 'InitialValue 1))) which is basically the same as our counter above. : (def 'counter (make-counter 0 1)) - counter : (counter) - 1 : (counter) - 2 Cheers, - Alex -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED] -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED]