On Sat, 10 Oct 2009, Alexander Burger wrote:
thanks for your proposal.
However, as I explained in another mail, I would definitely not change
the current behavior of 'list' or 'cons' (and most other functions in
I'm uncertain if '() is actually (NIL . NIL) so I'm not going to list
the cons' examples.
No, these are different things. () is converted by the reader as a
reference to the internal symbol 'NIL'. (NIL . NIL), which is the same
as (NIL), is a cell containing references to NIL in the CAR and CDR
(cons) is my standard way to create a fresh cell.
I know why this works this way. In pL's VM, every list is parsed until
there's an empty CDR (retreiving CDR returns NIL). Since there are
^ call this "atomic CDR"
functions that MUST take at least one argument; when they are called
with no argument, they will try to read NIL's CDR, and therefore use NIL
as arguments, since (cdr NIL) -> NIL
Here are a couple of solutions for this issue, you pick:
1. Make it error when (cdr NIL) (increases complexity and decreases
2. Make pL check on every step if the current argument is actually the last
CAR (naive and maybe slow).
3. Make pL check the amount of arguments provided and return NIL if they are
not enough for the function to do it's job. (slightly increases complexity)
4. Bury the topic.
A good roundup :-)
Points (1) and (2) would actually be rather stupid and useless, but can
be seen in some Lisp and Scheme implementations.
Right, that's why I listed them :-)
The original design of picoLisp put a lot of effort into the handling of
NIL. While NIL is in other Lisps just a symbol, it has a dual nature in
picoLisp (see "doc/structures" and "doc64/structures"):
|'LIN'| / | / | / |
While it is a symbol physically (the pointer is at an multiple of the
cell size plus half a cell), accessing the pointer with CAR (offset
zero) and CDR (offset half a cell size) is legal and will always return
NIL again. This allows a very fast traversal of lists, without the need
for checking for end-of-list.
So (3) comes without any cost.
I'll dig this topic further :-)
Anyway, I just couldn't resist the temptation to try to implement
solution nº 3, so I grabbed the sources, segfaulted the hell out of it
when I tried to avoid repeating code, and after a long while of ERTCL
(edit, recompile, test, cuss, loop), I decided to leave it like that for
now, and ask for a revision.
Well, first of all, a function that counts arguments before evaluating
them should be avoided like hell. This was the main reason for rewriting
picoLisp in assembly language (explained in "doc64/README"). And,
fortunately, it is also not necessary. Usually a simple
atom (X CDR)
will tell you if there are any (or more) arguments.
Oh well, missed that, but I wanted to get the hang of pLAsm and this seemed to
be a nice exercise to warm up so..
Besides this, what you wrote looks really good!
+### Internal function ###
+(code 'argLen 2)
+ push X
+ push Y
+ ld Y (X CDR) # Next cell
+ cmp Y X # Circular?
+ jz lengthT # Yes
+ add E (hex "10") # Increment counter
+ ld Y X # Keep list head <- This should be before the "Circular?" check?
Seems it's still too early for me to do full fledged asm programming yet.