Prev: Mistake in the specification of rotatef ?
Next: [ann] LTK based libraries Runtime Library 3.0 and Gestalt Items 1.1
From: John Thingstad on 19 Nov 2009 17:07 The Thu, 12 Nov 2009 18:40:03 +0530, Madhu wrote: > | I disagree. This article is spot on in adressing the issues which | > cause side effects. It is more sad to peolple like youself so | > unappriciative. > > However the point is CL's macro system is not hygienic and CL is not > about restricting side effects. No, the interesting point is to know what causes side-effects and how you can get around them. Less interesting is that you can implement a unhygienic macro facility in a hygienic one. > The fact that the CL macro system is > powerful enough to implement a hygienic subset is not an especially > interesting result, in the same sense that you can always use a more > powerful system to build a more restricted less expressive system. But Hygienic macros are not more restrictive. It is more work to introduce side effects but you can certainly do so. In fact the paper describes how this is done. All it really comes down to is: Do you spend more time writing code to avoid side effects in CL than you would writing code to produce them in Scheme? Not spending a lot of time writing macros in Scheme I can't answer that. -- John Thingstad
From: Ron Garret on 19 Nov 2009 19:46 In article <2009111921551816807-tfb(a)cleycom>, Tim Bradshaw <tfb(a)cley.com> wrote: > On 2009-11-19 05:26:34 +0000, Kenneth Tilton <kentilton(a)gmail.com> said: > > > No, this guy is a Java fruitcake who thinks he has black helicopters he > > can send after you. Nuff said? > > Given up Java, now using Python as it's more fashionable. Ruby is > next, I think. The helicopters are a real problem - used to be funded > by those nice bank people but they're all civil servants now, and it > appears that the tfb helicopter co was not too big to fail. We can > probably still afford to have Madhu abducted... > > Now, seriously. I have a program in mind which: > * will need to parse XML config files (realistically: I'd use sexps if > I have the choice but the target market will not accept that. > * needs to run on a wide variety of Unix/Linux platforms (recompilation > is fine) including very old versions of the OS > * needs to be pretty intimate with POSIX > * probably will ship source but do not want GPL contagion > > i was thinking of doing this in Java (and shipping a JRE it works on, > the way everyone else does), but there seems to be no serious posix > bindings for Java at the level I need (things like working out the > current UIDs/GIDs of the process, calling setuid &c). So I'm thinking, > realistically, Perl (and ship a perl runtime with it). Noooooooooo!!! Perl is a freakin' nightmare. (That's one thing Erik and I definitely agreed on.) > > Looks to me like the only Lisp option would be CLISP. Try CCL (Clozure Common Lisp). I believe you will find it meets all your needs. rg
From: Kaz Kylheku on 19 Nov 2009 20:50 On 2009-11-19, Tim Bradshaw <tfb(a)cley.com> wrote: > Now, seriously. I have a program in mind which: > * will need to parse XML config files (realistically: I'd use sexps if > I have the choice but the target market will not accept that. > * needs to run on a wide variety of Unix/Linux platforms (recompilation > is fine) including very old versions of the OS > * needs to be pretty intimate with POSIX > * probably will ship source but do not want GPL contagion You could use C. Seriously. Just base it on the internals of my new txr program. http://savannah.nongnu.org/projects/txr Running on very old versions should be fine. You do need the <wchar.h> header from C95. Other than that, just C89 and POSIX.1 and POSIX.2 is needed. Portabilty could be a bit dodgy due to the GC. Works on x86_64 and i386. Intimate with POSIX: check. Ship source: New BSD license, no GPL: check. You've got: - everything written in C, using C functions, with C local variables on the real stack. - dynamic typing and garbage collection. - gc scans the stack, so no special protocol to ``hold'' local variables to protect them from gc. - simple mechanism to register globals into the root set. - hashes with weak keys and values (poorly tested, but there) - all text in wide characters, and UTF-8 streams. - string streams, and a simple formatter. - simple regular expression engine with an s-exp input language, which handles Unicode character classes. - symbols - nonlocal transfers and exceptions - very basic library, but easy to extend. It's easy to add your custom objects whose guts are written in C and play along with the garbage collected world. A flavor of the code: /* exhibit 0: formatting ``nao'' is a special symbol used for terminating variable argument lists; helps variadic functions detect errors. nao is a distinct bit pattern from any object, including nil. If format sees nao when extracting an argument, it throws an exception. If format does not see nao as the next argument after processing the format string, ditto. So format is a lot more safe that C printf. lit() is a macro. It efficiently turns a string literal into a first-class object, without consing any memory, so the format function's API does not use C strings. L is added to the literals, making them wide strings (wchar_t chars). */ std_output performs UTF-8 encoding, outputting bytes. */ { format(std_output, lit("Hello, ~a!\n"), lit("world!"), nao); ... } /* exhibit 1: lispy code Note: this is not at all a normal Lisp-like eval and not in the basic library; it's a concept specific to the txr application. No evaluator is provided in the library, since code is written in C and compiled. identity_f is a "pre-cooked" function object for identity, so we don't have to cons it up when we need it. regexp means regex_p: ``is a regex'' :) */ obj_t *eval_form(obj_t *form, obj_t *bindings) { if (!form) return cons(t, form); else if (symbolp(form)) return assoc(bindings, form); else if (consp(form)) { if (car(form) == quasi) { return cons(t, cat_str(subst_vars(rest(form), bindings), nil)); } else if (regexp(car(form))) { return cons(t, form); } else { obj_t *subforms = mapcar(bind2other(func_n2(eval_form), bindings), form); if (all_satisfy(subforms, identity_f, nil)) return cons(t, mapcar(func_n1(cdr), subforms)); return nil; } } if (stringp(form)) { return cons(t, form); } return cons(t, form); } /* exhibit 2: posixy ooops, I see a bug here: the handle == 0 case should throw a file_err; someone is trying to read a directory stream with no handle. */ static obj_t *dir_get_line(obj_t *stream) { DIR *handle = (DIR *) stream->co.handle; if (handle == 0) { return nil; } else { for (;;) { struct dirent *e = readdir(handle); if (!e) return nil; if (!strcmp(e->d_name, ".") || !strcmp(e->d_name, "..")) continue; return string_utf8(e->d_name); } } } /* exhibit 3: snippet illustrating named blocks use */ { uw_block_begin(block_symbol, result_variable); /* code dynamically in here uses uw_block_return(<symbol>, <value>) to dynamically exit from this block. */ uw_block_end; /* result_variable holds block return value */ } /* exhibit 4: long snippet showing flavor of combined exception catching and unwind-protect. NOTE: this code is /interpreting/ a language that provides try/catch/finally, that's why there are references to these names. Don't get confused. The items of interest here are the uw_catch_begin, uw_catch, uw_do_unwind and uw_unwind macros. uw_catch_begin/end wrap the whole protected block. catch_syms is a list of exception symbol types, subtypes of which are caught; exsym is the name of a variable that is defined by the macro which will hold the actual type of the exception caught, exvals is the name to use for the variable that holds the exceptino value. The uw_catch (..., ...) catch block is invoked when a matching exceptino is caught. the uw_unwind block is run always whenever a non-local jump passes through. The uw_do_unwind; macro is a little hack. In the normal return case from the protected code, or in the case of catching, it provides the glue to run the unwind cleanup code also in the uw_unwind block. But not only a hack, this gives you a choice to always do the cleanup, or skip it. */ { uw_block_begin(nil, result); uw_catch_begin(catch_syms, exsym, exvals); { result = match_files(try_clause, files, bindings, data, num(data_lineno)); uw_do_unwind; } uw_catch(exsym, exvals) { { obj_t *iter; for (iter = catch_fin; iter; iter = cdr(iter)) { obj_t *clause = car(iter); obj_t *type = first(second(clause)); obj_t *params = second(second(clause)); obj_t *body = third(clause); obj_t *vals = if3(listp(exvals), exvals, cons(cons(t, exvals), nil)); if (first(clause) == catch) { if (uw_exception_subtype_p(exsym, type)) { obj_t *all_bind = t; obj_t *piter, *viter; for (piter = params, viter = vals; piter && viter; piter = cdr(piter), viter = cdr(viter)) { obj_t *param = car(piter); obj_t *val = car(viter); if (val) { bindings = dest_bind(bindings, param, cdr(val)); if (bindings == t) { all_bind = nil; break; } } } if (all_bind) { cons_bind (new_bindings, success, match_files(body, files, bindings, data, num(data_lineno))); if (success) { bindings = new_bindings; result = t; /* catch succeeded, so try succeeds */ if (consp(success)) { data = car(success); data_lineno = c_num(cdr(success)); } else { data = nil; } } } break; } } else if (car(clause) == finally) { finally_clause = body; } } } uw_do_unwind; } uw_unwind { obj_t *iter; /* result may be t, from catch above. */ if (consp(result)) { /* We process it before finally, as part of the unwinding, so finally can accumulate more bindings over top of any bindings produced by the main clause. */ cons_bind (new_bindings, success, result); if (consp(success)) { data = car(success); data_lineno = c_num(cdr(success)); } else { data = nil; } bindings = new_bindings; } if (!finally_clause) { for (iter = catch_fin; iter; iter = cdr(iter)) { obj_t *clause = car(iter); if (first(clause) == finally) { finally_clause = third(clause); break; } } } if (finally_clause) { cons_bind (new_bindings, success, match_files(finally_clause, files, bindings, data, num(data_lineno))); if (success) { bindings = new_bindings; result = t; /* finally succeeds, so try block succeeds */ if (consp(success)) { data = car(success); data_lineno = c_num(cdr(success)); } else { data = nil; } } } } uw_catch_end; uw_block_end; if (!result) return nil; if ((spec = rest(spec)) == nil) break; goto repeat_spec_same_data; }
From: mdj on 19 Nov 2009 22:50 On Nov 20, 7:55 am, Tim Bradshaw <t...(a)cley.com> wrote: > Now, seriously. I have a program in mind which: > * will need to parse XML config files (realistically: I'd use sexps if > I have the choice but the target market will not accept that. > * needs to run on a wide variety of Unix/Linux platforms (recompilation > is fine) including very old versions of the OS > * needs to be pretty intimate with POSIX > * probably will ship source but do not want GPL contagion That's not enough information to base a recommendation on, but I would say if you're going to have to ship a runtime, CL would be ideal. Other than that, you mentioned Python. Most of your target platforms will already have an implementation installed so as long as you target an older edition (say 2.4) you'll be fine. Unless of course you need to be 'intimate' with POSIX threads, but like I said not enough information. Matt
From: Ron Garret on 20 Nov 2009 00:53
In article <20091119165505.75(a)gmail.com>, Kaz Kylheku <kkylheku(a)gmail.com> wrote: > On 2009-11-19, Tim Bradshaw <tfb(a)cley.com> wrote: > > Now, seriously. I have a program in mind which: > > * will need to parse XML config files (realistically: I'd use sexps if > > I have the choice but the target market will not accept that. > > * needs to run on a wide variety of Unix/Linux platforms (recompilation > > is fine) including very old versions of the OS > > * needs to be pretty intimate with POSIX > > * probably will ship source but do not want GPL contagion > > You could use C. > > Seriously. Just base it on the internals of my new txr program. Greenspun's tenth in all its horrible glory. rg |