Re: PicoLisp and SWIG

2013-05-16 Thread Tomas Hlavaty
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

2013-05-16 Thread Thorsten Jolitz
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...)

2013-05-16 Thread Alexander Burger
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?

2013-05-16 Thread Rowan Thorpe
  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?

2013-05-16 Thread Alexander Burger
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?

2013-05-16 Thread Jon Kleiser

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...)

2013-05-16 Thread Alexander Burger
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?

2013-05-16 Thread Alexander Burger
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...)

2013-05-16 Thread Samuel Dennis Borlongan
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?

2013-05-16 Thread Jon Kleiser

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...)

2013-05-16 Thread Alexander Burger
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...)

2013-05-16 Thread Alexander Burger
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

2013-05-16 Thread Martin Curran
Hello Martin Curran martin.tho...@gmail.com :-)
You are now subscribed


-- 
UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe


Re: PicoLisp and SWIG

2013-05-16 Thread Tomas Hlavaty
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?

2013-05-16 Thread Rowan Thorpe
 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

2013-05-16 Thread Oskar Wieland

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?

2013-05-16 Thread Alexander Burger
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)

2013-05-16 Thread Alexander Burger
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