Re: Iteration in lisp
- From: lisp1.3.CalRobert@xxxxxxxxxxxxxxx (Robert Maas, http://tinyurl.com/uh3t)
- Date: Sat, 26 Apr 2008 18:36:17 -0700
From: Kent M Pitman <pit...@xxxxxxxxxxx>
When I speak of Common Lisp, I generally mean "any Common Lisp";
when I want to talk about a particular implementation, I tend to
identify that.
You're implying that's a good practice, being clear as to
*every*conforming*CL* vs. the CL which I happen to use this year,
and I agree it's good practice.
I have recently remarked that I don't like the default CL
treatment of SETQ and that I tend to program in a non-portable
fashion.
I haven't seen that, and now that you mention it I'm very curious.
Would you possibly create a Web page where you have links to
anything you've posted on this topic plus maybe a little "glue"
(introductory) text, and then post the URL for your Web page here?
I can only guess that maybe you don't like the way that
interpretation or JIT-compilation of a SETQ form of an undeclared
unbound symbol automatically declares it SPECIAL? If not that, I
can't guess at all.
I try to make my CL code totally portable (except for
non-conforming implementations such as the crap I downloaded to my
Mac), but since I have no way to test it on anything except CMUCL I
can't really be sure it's portable. I do try as hard as possible to
read the documentation and *strictly* conform to what it says I am
guaranteed to be allowed to do, and avoid (usually anyway) using
"features" that I discover CMUCL also has which aren't in the
standard documentation. For example I totally avoid using COERCE
and any other political-compromise crocks I discover in my code,
and I use TYPE-OF only for interactive debugging (including
higher-level debugging aids I write). I'm curious how you
deliberately program in a non-portable way, especially after you
played such a large role in the ISO/ANSI standard.
Oh, and when I really do need to use a non-standard function,
something CMUCL has which isn't in the standard, I would like to
isolate that code to a special file that contains
advertised-non-portable code. But maybe I am not so diligent as I
should be, because EXT:RUN-PROGRAM is so immensely useful all over
the place, and it just naturally slips in lots of places.
Currently/recently I use it in:
2007-3-spamu.lisp: (ext:run-program "/usr/local/bin/readmsg"
2007-3-whois.lisp: (ext:run-program "/usr/bin/whois"
2007-4-lynx.lisp: (ext:run-program "/usr/local/bin/lynx"
2007-4-whois.lisp: (ext:run-program "/usr/bin/whois"
2007-4-whois.lisp: (ext:run-program "/usr/bin/whois"
2007-4-whois.lisp: (ext:run-program "/usr/bin/whois"
2007-5-dig.lisp: (ext:run-program "/usr/bin/dig" (list domain "mx")
2007-5-dig.lisp: (ext:run-program "/usr/bin/dig" (list hostname "a")
My older software developed from 2001 through appx. 2006, whereupon
just about everything related to fighting spam (filtering e-mail,
auto-complaining, etc.) was in one huge file, before I started
refactoring the files by putting each small module in a separate
sourcefile, none larger than 30k bytes (the maximum for copy+paste
up/download on my Mac), had a lot more uses of it, too many for you
to see, but with duplicaes removed maybe you won't go blind:
2001.Nov.lisp: (ext:run-program "/bin/mv"
2001.Nov.lisp: (ext:run-program "/bin/sh" (list)
2001.Nov.lisp: (ext:run-program "/usr/bin/dig" (list domain "a")
2001.Nov.lisp: (ext:run-program "/usr/bin/dig" (list domain "mx")
2001.Nov.lisp: (ext:run-program "/usr/bin/mail" (list "-I" "-f" "tmpmbox")
2001.Nov.lisp: (ext:run-program "/usr/bin/mail" progargs :output t :input sichan)
2001.Nov.lisp: (ext:run-program "/usr/bin/telnet"
2001.Nov.lisp: (ext:run-program "/usr/bin/whois"
2001.Nov.lisp: (ext:run-program "/usr/local/bin/lynx"
2001.Nov.lisp: (ext:run-program "/usr/local/bin/readmsg"
2001.Nov.lisp: (ext:run-program "/usr/sbin/traceroute"
Hmmm, looking at that one example where I say (list) gives me the
idea that in addition to my eventual essay on the intention of
atomic data types (such as using unsigned integer to emulate a
bitmask or a boolean or a US-ASCIi character code or a UniCode
codepoint or a UCS-8 toke), maybe I should also write an essay on
expressing the intention of data by what constructor you use for
it. For example, in that call to ext:run-program, the second
parameter is a list of Unix shell parameters to pass to the called
program, and in this case I pass the empty list, so it makes sense
to say (list) or '() instead of NIL to express my deep intention of
conforming to the API for ext:run-program. Both of these essays
would become companions to your super essay about intention of
copying from a handle on a CONS cell, depending on whether that
CONS cell is considered an isolated cell or part of a proper list
or part of an assoc list or part of a binary tree etc.
I just had a horrible thought: What if the original implementors of
Lisp had recognized this problem of the same kind of pair-cell
being used to build several different kinds of data structures,
with all ambiguity as to what is the container and what is the
contained within each kind of structure, so they decided instead of
having just one kind of CONS cell, at least four kinds, each with
its own flavor of constructor, and each printing with a different
favor of dot:
(pair-cons a d)
=> (a .p. d)
(list-cons e1 (list-cons e2 nil))
=> (e1 .l. (e2 .l. nil))
= (e1 e2)
(a-cons (ac-cons k1 v1) (a-cons (ac-cons k2 v2) nil))
=> ((k1 .ac. v1) .a. ((k2 .ac. v2) .a. nil))
= #a((k1 . v1) (k2 . v2))
Corresponding different flavors of the LIST vararg-function:
(llist a b c)
(alist (ac-cons k1 v1) (ac-cons k2 v2))
I think the problem with intention that can't be determined by the
runtime system is not as bad a problem as the alternative. So long
as every newbie reads your 'intention' essay and really understands
it, I think we can live with a single type of CONS-cell that fails
to express the intention of the structure it's part of. Maybe it's
actually a good thing that newbies must deal with this runtime-type
ambiguity (regarding intention) very early on, so they get used to
the idea that in a flexible extendable system such as Lisp it's
common to re-use an old data type to emulate a new abstract data
type without needing to get the new intention formally registered
with the vendor, you just hack the new data type and express your
intention by the extra layer of software for your new ADT. In other
words, never call CAR or CDR or CONS directly from application-level
software. Call those primitives *only* from the implementation of a
new API. So what you do is: Design an ADT and describe an API for
it, then implement that API using CL primitives, and then from
application-level code you always call the API functions instead of
the underlying CL primitives.
OK, I have a riddle for everyone to brainstorm about.
You want to build a list (the usual, CONS-cells CDR-linked),
where each element is either a tree or a list or an alist,
and you want to call (mapcar #'COPY-DO-THE-RIGHT-THING thatList),
where it does copy-list or copy-cons or copy-alist as appropriate.
Obviously it won't work the obvious way, as Kent's essay explains.
So how can you design things so that this *will* work??
.
- Follow-Ups:
- Re: Iteration in lisp
- From: Pascal Bourguignon
- Re: Iteration in lisp
- From: Kent M Pitman
- Re: Iteration in lisp
- References:
- Iteration in lisp
- From: rigaha@xxxxxxxxx
- Re: Iteration in lisp
- From: Kent M Pitman
- Re: Iteration in lisp
- From: John Thingstad
- Re: Iteration in lisp
- From: Kent M Pitman
- Iteration in lisp
- Prev by Date: Re: How much of a lisp compiler is written in lisp ?
- Next by Date: Re: Why does Lisp (SBCL) produce so huge executables?
- Previous by thread: Re: Iteration in lisp
- Next by thread: Re: Iteration in lisp
- Index(es):
Relevant Pages
|