Re: PicoLisp and SWIG
Hi Thorsten, Maybe you should do a bit more publicity and marketing for your libraries? You have some quite interesting stuff in your 'backcatalog' that is not at all linked to or documented in the PicoLisp Wiki. yeah, but it is much more interesting to write code;-) indeed, this would be just a simple elisp function or even a keyboard-macro. Yes, this is staightforward for C but not for C++. One of the major problems for me is that most interesting libraries are actually object-oriented C++ class libraries, so the direct correspondence between C function signature and PicoLisp list is lost. So the (giant) first task is to port C++ classes to C function calls. SWIG is able to do this by exposing the internal of the user defined object in a lot of C function, e.g. a getter and a setter function for each instance variable and one C function of each (overloaded) constructor and one C function for each method etc. Probably no magic at work, but one should probably understand the inner working of C++ to write such transformation code. I think it's too much work for too little benefit. The result would be fragile. C++ is too complex. IIRC I used minipicolisp for it, which didn't support dlopen etc. so I compiled the glue code directly into the picolisp executable. I think the main reason for using minipicolisp was that I had a 64 bit OS and didn't want to polute it with so many 32 bit libraries and their dependencies just for testing the FFI. I think this FFI code could still be useful to people that want to easily interface picolisp with C. For the 64 picolisp, which came later and used completely dynamic FFI, it should be reasonably easy to make another (64bit) version of ffi.l which would preserve the FFI interface (use the .ffi files) but instead of going the C route, it could directly use the dynamic FFI capabilities of 64 bit picolisp. At the moment, people need to decide whether to use 32 bit or 64 bit picolisp. This decision impacts how to do FFI, which is a shame. The point here is that there could be unified FFI interface across all types of picolisp. (Well, except the java version, I suppose.) I'm not sure which 'dynamic FFI capabilities' you mean, but 64bit picolisp has the (native) function that seems to me like a 'one function ffi' to C code. When its only about C functions with primitive args and return values, they can be translated directly into native calls. Yes, the function 'native'. Unfortunately whenever I search for interesting C libraries, e.g. for data mining or whatever, I find C++ class hierarchies, sometimes with dozens or hundreds of classes and hundreds of thousands of methods. One solution even though not so general, could be to write some kind of simple interpreter (repl) on top of the library and communicate/control it from picolisp via a text protocol/language. Many sophisticated scientific libraries often have such a repl already. So as I see it, I still have to use SWIG to turn these class hierarchies in plain functions calls, and then I can use PicoLisp 'native' calls as wrappers. Would be great though to have a ffi.l that knows how to deal with C++. Yes, that seems like a good plan to attack the problem. I imagine though that the generated C will be pretty bloated mess. Cheers, Tomas -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: PicoLisp and SWIG
Tomas Hlavaty t...@logand.com writes: Hi Tomas, So as I see it, I still have to use SWIG to turn these class hierarchies in plain functions calls, and then I can use PicoLisp 'native' calls as wrappers. Would be great though to have a ffi.l that knows how to deal with C++. Yes, that seems like a good plan to attack the problem. I imagine though that the generated C will be pretty bloated mess. First experiments with sample C++ files have been encouraging so far. I use this SWIG command line, which produces, besides the probably bloated C code, a kind of 'Lisp pseudo code' too, that should be easily transformed into 'native calls: ,-- | swig -cffi -c++ example.i `-- There are many other options, e.g. -python, -java,-alegrocl etc., but this one seemed to be the most straigt forward to me. But I'm not sure how complete the C++ coverage is, I think templates are not supported. On the other hand, it seems that by the end of this summer, ANSI C is added as a target language to SWIG, which would probably be the most straight forward option to prepare C++ class libraries for 'native calls. -- cheers, Thorsten -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: Bouncing on trampolines (so cool...)
Hi all, I didn't bother with trampolines so far, but add some comments to On Thu, May 16, 2013 at 12:00:20AM +0800, Samuel Dennis Borlongan wrote: ... http://stackoverflow.com/questions/12186672/how-can-i-prevent-my-ackerman-function-from-overflowing-the-stack ... The bad thing with overflowing your stack is ... well, overflowing your stack. But you may as well overflow your heap, so nothing is gained. As it is recommended for PicoLisp anyway to set 'ulimit -s unlimited', the stack will use as much memory as is physically available, like the heap. The recursive version is usually faster than the one using an explicit stack, but uses perhaps a little bit more memory because each recursion level takes several stack lokations. Let's take the standard Ackermann function (de ack (M N) (cond ((=0 M) (inc N)) ((=0 N) (ack (dec M) 1)) (T (ack (dec M) (ack M (dec N ) ) Eliminating tail-recursion gives (de ack2 (M N) (loop (T (=0 M) (inc N)) (NIL (=0 N) (ack (dec M) (ack M (dec N (dec 'M) (one N) ) ) Both functions show roughly the same speed, : (bench (ack 4 1)) 249.465 sec - 65533 : (bench (ack2 4 1)) 252.487 sec - 65533 though the less-recursive function is slightly slower (as expected). If we go - as usually recommended - for the iterative version with an explict stack, (de ack3 (M N) (for (Stack (cons M) Stack) (if (=0 (setq M (pop 'Stack))) (inc 'N) (push 'Stack (dec M)) (if (=0 N) (one N) (push 'Stack M) (dec 'N) ) ) ) ) things get significantly slower: : (bench (ack3 4 1)) 312.028 sec - 65533 The fastest is - as expected and described - the cheating version: (de ack4 (M N) (for (Stack (cons M) Stack) (cond ((=0 (setq M (pop 'Stack))) (inc 'N)) ((= 1 M) (inc 'N 2)) ((= 2 M) (setq N (+ 3 (* 2 N (T (push 'Stack (dec M)) (if (=0 N) (one N) (push 'Stack M) (dec 'N) ) ) ) ) ) With that we get : (bench (ack4 4 1)) 0.000 sec - 65533 : (bench (length (ack4 4 2))) 0.981 sec - 19729 (de ack/t (M N R S) (default R '()) (if ( (length R) 0) (unless S (setq M (pop 'R) ) ) (push 'R M) ) (cond ((=0 (length R) ) (done N) ) ((= M 0) (continue ack/t M (+ N 1) R) ) ((= M 1) (continue ack/t M (+ N 2) R) ) ((= M 2) (continue ack/t M (+ (* N 2) 3) R) ) ((= N 0) (continue ack/t (- M 1) 1 R T) ) (T (push 'R (- M 1) ) (continue ack/t M (- N 1) R T) ) ) ) Honestly, I hate my Ackermann implementation, not because its performance is bad ( (trampoline ack/t 3 8000) takes 1.970 sec and 10.287 sec in 32-bit and ersatz, respectively) Are you sure? Here I get : (bench (length (ack4 3 8000))) 0.018 sec - 2410 and even on my humble Netbook with a slow Atom CPU (pil32): : (bench (length (ack4 3 8000))) 0.213 sec - 2410 ♪♫ Alex Side note (though this doesn't really matter for the speed): It is never wise to use 'length' to detect short lists. Better replace (if (=0 (length R)) ..)with (if R ..) or (if (= (length R) 3) ..) with (if (cddr R) ..) to avoid possibly counting along long lists. -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: How to set IP address for socket?
Thanks! The 'make' went fine now. However, when I try to run my web app now, I get IP bind error: Address already in use. ;-) I think I may have to bother C9 Support again. Ah, but perhaps this is (partially) good news, because it seems to have taken the address! :) Just throwing in an observation in case it hasn't already occurred to you - the Address already in use error might well not be a picolisp or C9 problem at all, but that you are reconnecting to the socket without having set the SO_REUSEADDR option (or equivalent). Without it you can't reconnect to an already connected socket, e.g. for about 90 seconds on Linux, or similar duration on other platforms (must wait for OS to release socket based on its own view of things). If that is totally unhelpful or irrelevant then sorry for the line-noise ;-) Rowan Thorpe -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: How to set IP address for socket?
Hi Rowan, Just throwing in an observation in case it hasn't already occurred to you - the Address already in use error might well not be a picolisp or C9 problem at all, but that you are reconnecting to the socket without having set the SO_REUSEADDR option (or equivalent). Without it you can't reconnect to an already connected socket, e.g. for about 90 seconds on Linux, or similar duration on other platforms (must wait That's right. But in this case the function in question ('port') does indeed set this option. However, it still might be the case that some other service is already listening at that port, perhaps even some not-yet-terminated instance of your application. You can find out the culprit with $ lsof -i :8080 COMMANDPID USER FD TYPE DEVICE SIZE/OFF NODE NAME picolisp 20278 app 16u IPv6 2098603 0t0 TCP *:http-alt (LISTEN) ♪♫ Alex -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: How to set IP address for socket?
Hi Alex Rowan, As far as I can see, there is no other process listening on 8080 at the moment when I get this Address already in use. However, I've just managed to put together a tiny Ruby server (found something on stackoverflow) that works. It uses server = TCPServer.open(host, port) where 'host' is 127.6.26.129 and 'port' is 8080. Right now it's available here http://demo-project.jkleiser.c9.io/, but not for very long ... When I do the lsof -i :8080 now, I get this: COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME ruby16690 517cfc7750044649680001965u IPv4 21717622 0t0 TCP 127.6.26.129:webcache (LISTEN) /Jon On 16-05-13 15:34 , Alexander Burger wrote: Hi Rowan, Just throwing in an observation in case it hasn't already occurred to you - the Address already in use error might well not be a picolisp or C9 problem at all, but that you are reconnecting to the socket without having set the SO_REUSEADDR option (or equivalent). Without it you can't reconnect to an already connected socket, e.g. for about 90 seconds on Linux, or similar duration on other platforms (must wait That's right. But in this case the function in question ('port') does indeed set this option. However, it still might be the case that some other service is already listening at that port, perhaps even some not-yet-terminated instance of your application. You can find out the culprit with $ lsof -i :8080 COMMANDPID USER FD TYPE DEVICE SIZE/OFF NODE NAME picolisp 20278 app 16u IPv6 2098603 0t0 TCP *:http-alt (LISTEN) ♪♫ Alex -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: Bouncing on trampolines (so cool...)
On Thu, May 16, 2013 at 01:33:54PM +0200, Alexander Burger wrote: : (bench (ack 4 1)) 249.465 sec - 65533 : (bench (ack2 4 1)) 252.487 sec - 65533 though the less-recursive function is slightly slower (as expected). Oops, forget that! Not as expected ... the opposite would be expected. But the values are very close anyway. ♪♫ Alex -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: How to set IP address for socket?
Hi Jon, stackoverflow) that works. It uses server = TCPServer.open(host, port) where 'host' is 127.6.26.129 and 'port' is 8080. Right now I see. So my proposal of calling inet_pton() was not correct :( I have no idea at the moment. Somebody (me?) must dig into TCP networking (again). Haven't touched that for a while. Anybody who knows a direct solution? ♪♫ Alex -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: Bouncing on trampolines (so cool...)
Re: side-note (bench (length (ack4 3 8000))) (32-bit Cygwin) 0.070 sec (bench (length (trampoline ack/t 3 8000))) (32-bit Cygwin) 2.010 sec (bench (length (trampoline ack/t 3 8000))) (64-bit Ersatz on Java 8, before =0 and length invocation removal) 9.625 sec (bench (length (trampoline ack/t 3 8000))) (64-bit Ersatz on Java 8, after =0 invocation removal) 4.981 sec (bench (length (trampoline ack/t 3 8000))) (64-bit Ersatz on Java 8, after =0 and length invocation removal) 0.123 sec I therefore conclude that ack/t was programmed badly. My fault. Also, efficient programming in Ersatz apparently _relies_ on things that might speed up a little. Trampolines are still fun, though. New version: (de ack/t (M N R S) (default R '()) (if R (unless S (setq M (pop 'R) ) ) (push 'R M) ) (cond ((not R) (done N) ) ((= M 0) (continue ack/t M (+ N 1) R) ) ((= M 1) (continue ack/t M (+ N 2) R) ) ((= M 2) (continue ack/t M (+ (* N 2) 3) R) ) ((= N 0) (continue ack/t (- M 1) 1 R T) ) (T (push 'R (- M 1) ) (continue ack/t M (- N 1) R T) ) ) ) Thanks for the comments! P.S. For the sake of context and gratuitous post-scripts, most of my work is done using Ersatz PicoLisp with LispIDE / Notepad++ on Windows workstations that run pre-release Java 8 and 108-tab Firefox. Again, thanks! Samuel Dennis R. Borlongan On Thu, May 16, 2013 at 7:33 PM, Alexander Burger a...@software-lab.dewrote: Hi all, I didn't bother with trampolines so far, but add some comments to On Thu, May 16, 2013 at 12:00:20AM +0800, Samuel Dennis Borlongan wrote: ... http://stackoverflow.com/questions/12186672/how-can-i-prevent-my-ackerman-function-from-overflowing-the-stack ... The bad thing with overflowing your stack is ... well, overflowing your stack. But you may as well overflow your heap, so nothing is gained. As it is recommended for PicoLisp anyway to set 'ulimit -s unlimited', the stack will use as much memory as is physically available, like the heap. The recursive version is usually faster than the one using an explicit stack, but uses perhaps a little bit more memory because each recursion level takes several stack lokations. Let's take the standard Ackermann function (de ack (M N) (cond ((=0 M) (inc N)) ((=0 N) (ack (dec M) 1)) (T (ack (dec M) (ack M (dec N ) ) Eliminating tail-recursion gives (de ack2 (M N) (loop (T (=0 M) (inc N)) (NIL (=0 N) (ack (dec M) (ack M (dec N (dec 'M) (one N) ) ) Both functions show roughly the same speed, : (bench (ack 4 1)) 249.465 sec - 65533 : (bench (ack2 4 1)) 252.487 sec - 65533 though the less-recursive function is slightly slower (as expected). If we go - as usually recommended - for the iterative version with an explict stack, (de ack3 (M N) (for (Stack (cons M) Stack) (if (=0 (setq M (pop 'Stack))) (inc 'N) (push 'Stack (dec M)) (if (=0 N) (one N) (push 'Stack M) (dec 'N) ) ) ) ) things get significantly slower: : (bench (ack3 4 1)) 312.028 sec - 65533 The fastest is - as expected and described - the cheating version: (de ack4 (M N) (for (Stack (cons M) Stack) (cond ((=0 (setq M (pop 'Stack))) (inc 'N)) ((= 1 M) (inc 'N 2)) ((= 2 M) (setq N (+ 3 (* 2 N (T (push 'Stack (dec M)) (if (=0 N) (one N) (push 'Stack M) (dec 'N) ) ) ) ) ) With that we get : (bench (ack4 4 1)) 0.000 sec - 65533 : (bench (length (ack4 4 2))) 0.981 sec - 19729 (de ack/t (M N R S) (default R '()) (if ( (length R) 0) (unless S (setq M (pop 'R) ) ) (push 'R M) ) (cond ((=0 (length R) ) (done N) ) ((= M 0) (continue ack/t M (+ N 1) R) ) ((= M 1) (continue ack/t M (+ N 2) R) ) ((= M 2) (continue ack/t M (+ (* N 2) 3) R) ) ((= N 0) (continue ack/t (- M 1) 1 R T) ) (T (push 'R (- M 1) ) (continue ack/t M (- N 1) R T) ) ) ) Honestly, I hate my Ackermann implementation, not because its performance is bad ( (trampoline ack/t 3 8000) takes 1.970 sec and 10.287 sec in 32-bit and ersatz, respectively) Are you sure? Here I get : (bench (length (ack4 3 8000))) 0.018 sec - 2410 and even on my humble Netbook with a slow Atom CPU (pil32): : (bench (length (ack4 3 8000))) 0.213 sec - 2410 ♪♫ Alex Side note (though this doesn't really matter for the speed): It is never wise to use 'length' to detect short lists. Better replace (if (=0 (length R)) ..)with (if R ..) or (if (= (length R) 3) ..) with (if (cddr R)
Re: How to set IP address for socket?
Hi Alex, I'll be off-line for a couple of days. Have a nice weekend! /Jon On 16-05-13 16:38 , Alexander Burger wrote: Hi Jon, stackoverflow) that works. It uses server = TCPServer.open(host, port) where 'host' is 127.6.26.129 and 'port' is 8080. Right now I see. So my proposal of calling inet_pton() was not correct :( I have no idea at the moment. Somebody (me?) must dig into TCP networking (again). Haven't touched that for a while. Anybody who knows a direct solution? ♪♫ Alex -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: Bouncing on trampolines (so cool...)
Hi Samuel, (bench (length (trampoline ack/t 3 8000))) (64-bit Ersatz on Java 8, before =0 and length invocation removal) 9.625 sec (bench (length (trampoline ack/t 3 8000))) (64-bit Ersatz on Java 8, after =0 invocation removal) 4.981 sec (bench (length (trampoline ack/t 3 8000))) (64-bit Ersatz on Java 8, after =0 and length invocation removal) 0.123 sec Thanks! Interesting, I wouldn't have expected the effect be so big. The stacked list in 'R' must be very long then. ♪♫ Alex -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: Bouncing on trampolines (so cool...)
On Thu, May 16, 2013 at 04:33:49PM +0200, Alexander Burger wrote: though the less-recursive function is slightly slower (as expected). Oops, forget that! Not as expected ... the opposite would be expected. But the values are very close anyway. One more oops!! Though it doesn't matter much for the speed, I just noticed that 'ack2' was wrong! It recursed on 'ack' instead of itself ('ack2'). So for the records, this is the corrected version: (de ack2 (M N) (loop (T (=0 M) (inc N)) (NIL (=0 N) (ack2 (dec M) (ack2 M (dec N (dec 'M) (one N) ) ) ♪♫ Alex -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Subscribe
Hello Martin Curran martin.tho...@gmail.com :-) You are now subscribed -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: PicoLisp and SWIG
Hi Thorsten, use this SWIG command line, which produces, besides the probably bloated C code, a kind of 'Lisp pseudo code' too, that should be easily transformed into 'native calls: ,-- | swig -cffi -c++ example.i That is CFFI, portability layer for Common Lisp: http://cliki.net/cffi I've been using that a lot. It's good, but I'm not sure about C++ support. Cheers, Tomas -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: How to set IP address for socket?
Alexander Burger wrote: I see. So my proposal of calling inet_pton() was not correct :( I have no idea at the moment. Somebody (me?) must dig into TCP networking (again). Haven't touched that for a while. Jon, I think I might have found an explanation for the already bound error, and if it is this, then the error is not very appropriately worded (it might actually be a propagated inet_pton syntax error). On the inet_pton manpage I found this: BUGS: AF_INET6 does not recognize IPv4 addresses. An explicit IPv4-mapped IPv6 address must be supplied in src instead. Hopefully someone will get around to fixing that one day (I would have thought it would be a trivial fix...?!). The ipv6 address space is a (128bit) superset of the (32bit) ipv4 space anyway, so I don't see a reason *against* handling that syntax too... What happens if you do the same steps in the last version Alex told you to do, but instead of: : MyIpAddr asciz 127.6.26.129 you put the ipv6-mapped address for it: : MyIpAddr asciz :::127.6.26.129 ..? -- Rowan Thorpe -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Subscribe
Hello Oskar Wieland oskar.wiel...@gmx.de :-) You are now subscribed Hi, bitte melde mich fuer die email liste an. ein kleiner unwichtiger fehler: : (version) 3.1.2.0 C - (3 1 2 0) : (setq foo 1) - 1 : (foo) Segmentation fault (core dumped) lg oskar -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: How to set IP address for socket?
On Fri, May 17, 2013 at 02:05:10AM +0300, Rowan Thorpe wrote: you to do, but instead of: : MyIpAddr asciz 127.6.26.129 you put the ipv6-mapped address for it: : MyIpAddr asciz :::127.6.26.129 Thanks Rowan! This sounds like a very reasonable hint! ♪♫ Alex -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: Segmentation fault (Was: Subscribe)
Hi Oskar, bitte melde mich fuer die email liste an. Sure! It happened automatically already :) : (setq foo 1) - 1 : (foo) Segmentation fault (core dumped) I understand your worries, but this is actually a feature. In general, PicoLisp doesn't catch such errors, as this would induce relatively high runtime overhead, in contrast to their extremely rare occurrence in production programs. And, after all, Segmentation fault *is* an error message, generated by the hardware, isn't it? And you test your program at least once, don't you? Setting a symbol to a number (like '1' above) is perfectly legal. And calling a symbol with a numeric value means to call an internal function (i.e. a function pointer). However, at memory location '1' there is probably no function, but the interpreter cannot know this. To avoid potential dangers like the one above, where a variable is called as a function, PicoLisp recommends strongly to adhere to certain naming conventions: http://software-lab.de/doc/ref.html#conv You would use 'Foo' for locally bound symbols, and 'foo' for a global symbol (what a function typically is), and have no problem. Perhaps the FAQ http://software-lab.de/doc/faq.html#segfault should elaborate more on that? ♪♫ Alex -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe