Thanks for the reply. My apologies for so long a delay in replying. Work
jumped up and slapped me real hard last week. No time for anything else. :(
On 07/15/2017 05:52 AM, Alexander Burger wrote:
thanks for your long feedback and sharing your experiences!
I have spent a fair amount of the last 4 days playing with PicoLisp. I
Yess. From your code I see that you master PicoLisp already quite well! I
suspect that you gave up just a little bit too early.
Thank you. Certain difficulties like parens and deeply nested internally
function calls are slowly getting easier to read and recognize. I do
love the brutal consistency of Lisp. Certain things are a challenge at
first. But they get easier, and because of the absolute consistence they
can slowly be reasoned about. I haven't necessarily given up yet. But I
haven't made a decision for PicoLisp at this time. The beauty of Lisp
and the PicoLisp implementation are intriguing. One challenge I have is
that it feels much more primitive than what I am used to. I am used to
what many and myself consider the best IDE available, Smalltalk (Pharo).
It is wonderful and rich. The ability find the class or method which
will do exactly what you want is amazing. I struggle with purely
documentation or file based source code to find what I am looking for.
It may get easier with time. But I don't know.
: (scl 12)
Segmentation fault (core dumped)
Haha, right. Calling (*Scl) is a prefect way to segfault. Think about what it
means: It calls a *function* starting in memory at address 12!
This is what I mean about Pharo (Smalltalk). The VM/image will not let
that crash the environment. I could not have told that it called a
position in memory directly expecting to execute a function. I only was
wanting to know the value of *Scl. A naive understanding of Lisp is that
everything happens inside of parenthesis. So I naively did (*Scl)
instead of simply *Scl.
I would love the PicoLisp interpreter to handle stupid programmer errors
better. Now I speak as the stupid programmer, not as an interpreter
implementer having to do the protection from his stupidity. :)
I am okay if it throws me immediately into that ! commandline. I haven't
quite learned what that is all about either, or what I can do.
HOWEVER! The segfaults you observed in your program are NOT your fault! You
indeed found a bug in the bignum functions of PicoLisp, causing a crash upon a
certain combination of numeric arguments.
Strange that this was not detected earlier, I used a lot of test routines with
I cound not locate the exact location of the bug yet. It is a Heisenbug, because
it only occurs if the garbage collector runs in the right moment. I know this
because it all runs well if you call 'gc' *before* the test, e.g.
I will dig into it now, to find and fix it, and release a new PicoLisp version.
Thanks for finding it!
Glad I could be of help. That is one of the reasons I wrote the email
and not simply disappeared in silence. I thought to myself that if I
disappear in silence, that I am not being a very good user of open
source software and am not contributing the least thing that I could,
which is my experience.
As you spent already so much time on it, I feel that I should try it myself.
I rewrote parts of it to be more PicoLisp-like, as you violate some of the
PicoLisp programming rules and styles. I won't comment on the details, but paste
my own version below.
Thank you for this. I had hoped you would. I knew my code was naive and
most likely not idiomatic. It was having learned the least possible to
implement a version. I know that if I choose to use PicoLisp that there
is much more to learn include coding styles and idioms.
The new version is about 150 times faster. The main reason is that you used
'nth' to index into long lists again and again. Here on my notebook it
finishes the 100 reps in one and a half minutes:
$ time ./pil x.l +
A successful 100 rep run should give an
nsum: 11322.307098752284 and
navg: 0.393135663151121 within acceptable floating point differences.
Note that I get slightly different results, because I use '*/' instead of '/' in
the 'average' function. I believe that this is more correct, as '*/' rounds the
I worked on it for a while longer. What I find for me is that it is much
harder to reason about and to write error free code for floating point
numbers using the fixpoint system.
Part of the problem in your code with regards to the differences, is
that your loop indexes are still naive integers and not the fixpoint
: (inc '1 1.0)
: (+ 1.0 1.0)
These values for the calculations below should be identical. Since they
are not. The calculations are seemingly being seeded wrong values.
I have yet to get the createlist function to seemingly give me the
correct initial values.
(setq nl (createlist 28800))
: (format (nth nl 28800) *Scl)
Which is different from both of these and should be the first.
: (format (normalize 28800.0) *Scl)
: (format (normalize 28800) *Scl)
I made a small modification to your code. Added an argument to doit. And
I do not call it automatically. This way I can play in the interpreter
When I run your code on my laptop I get:
: (doit 100)
However, the app explodes in memory use. From the former 2.5mb (or was
it 3.5) of ram to 705mb of ram. So it went from one of the smaller
runtimes to the largest.
Now when I attempt to make changes to get it closer to the correct
values, the time to run goes up to over 30 minutes.
I don't have any code to show. I got busy at work and in my
experimenting I got lost in my code trying various things. It is much
harder to reason about than the normal integers and floating point of
the rest of the world. It isn't fun.
I take full responsibility that my code may be faulty. Because I
struggled with where I needed to change integer values 1 to a 1.0 or
not depending on what was happening. It is not easy to know and is error
prone. At least for me and my experience. Others may find it different.
Thanks for listening to my experiences. Hopefully you or someone can
find value in them.
Once again, I wish you the best on this project. As for me, I will
remain a Smalltalker (Pharo).
Now let me start the bug hunt.
PS: Here is my code:
(de average (L)
(*/ (sum prog L) (length L)) )
(de normalize (N)
(let NN (if (=0 N) 0.000123456789 N)
(while (<= NN 0.0001)
(setq NN (* 10 NN)) )
(while (>= NN 1.0)
(setq NN (*/ NN 10)) )
NN ) )
(de createlist (Lsize)
(let I 0
(link (normalize (inc 'I 1.0))) ) ) ) )
(de loop1calc (I J N)
(let V (*/ N (+ I N) (- J N) 0.1234567 `(* 1.0 1.0 1.0))
(normalize (*/ V V V `(* 1.0 1.0)) ) ) )
(de loop2calc (I J N)
(+ J 1.0)
(+ N N N)
`(* 1.0 1.0 1.0) ) ) )
(de loopN (Fun Lst Reps)
(let I 1.0
(let J 0
(Fun I (inc 'J 1.0) (car L)) ) )
Lst ) )
(inc 'I 1.0) ) )
*Nsum (sum prog Lst)
*Navg (average Lst) ) )
(de loop1 (Lst Reps)
(loopN loop1calc Lst Reps) )
(de loop2 (Lst Reps)
(loopN loop2calc Lst Reps) )
(de doit ()
(prinl "*Scl: " *Scl)
(let Reps 100
(let L (createlist (* 60 24 5 4))
(bench (loop1 L Reps))
(prinl "nsum: " (format *Nsum *Scl))
(prinl "navg: " (format *Navg *Scl))
(bench (loop2 L Reps)) ) ) )
(prinl "nsum: " (format *Nsum *Scl))
(prinl "navg: " (format *Navg *Scl)) )