David said:
Producing readable, hackable perl code was not one of the goals of my
program (as you might have guessed if you've seen any of the output!). I
had sort of figured that when you started using macros of any degree of
complexity then, whether you are translating to perl or not, you
wouldn't want to see the entirety of the macro expanded code anyway.
This is certainly the case with one largeish program I've written - the
amount of expanded code is enormous compared to the un-macro-expanded
code.
It does take some care when writing macros, but it's pretty much the
same as always being in "I might have to debug this macro" mode. If
you use meaningful variable names, and prune unused branches, it helps
a lot. Plus, if you allow the macros to insert comments into the
resulting code, the volume of Perl code isn't so daunting (kinda like
if you wrote it by hand).
Also, using (cond) statements, especially nested ones, produces
horrible looking perl code. They compile down to lots of trinary ifs
(a?b:c) in perl. The fact is, if I were programming in perl my program
just wouldn't be structured like that, whereas in lisp it seems a
natural thing to do.
Right, whereas in Lisp you might write (setf x (cond ...)), in Perl,
you'd write:
if (...) {... $x = 1;}
elsif (...) {... $x = 2;}
else {... $x = 3;}
In my compiler, the translators for compound expressions have three
modes: producing code for side-effect only, producing code used for
its value, and producing code to put the value in a specific location.
So, depending on context, cond might expand into if/elsif/else, or
trinary-if, or if it's complicated and/or nested, a call to an
anonymous lambda:
(sub { if (...) {... return 1;}
elsif (...) {... return 2;}
else {... return 3;} })->();
I guess readable code is nice to have if you are 'supposed to be'
programming in perl, but really want to use Lisp
Well, it wasn't so much "supposed to be", as much as the final product
had to be in Perl, so it would be easy to find someone later to
maintain it. No one had any problem with me using whatever expert
development tools I wanted, as long as the output was maintainable
as-is. But, pretty much, yeah
I'd be very interested in seeing the source code to your program if I may.
I'm sitting on it, pending my thinking about how much time/effort it
would take to make it useful to the general public, and if there's a
market for it or not. And it's a mess of unfactored hacks, because I
was concentrating on the systems I was supposed to be writing, not the
compiler itself.
I didn't intend it to be horrific! (well, not _too_ horrific
Horrific because it's a Lisp->Perl compiler, but not because of the
namespace issue?
I know it seems an odd thing to use a 1 namespace language to translate
to a 4 namespace language. The reason I'm doing the scheme thing as
opposed to the common lisp thing is that I just kind of like the 1
namespace approach. It seems to be a lot simpler and remove the
necessity for ways of dealing with different kinds of bindings. I guess
that's just personal preference. It does produce rather odd looking perl
code (lots of '$fn->(...)'), but as I say, I don't really care about
that. As long as it executes fast enough. I don't know if $fn->()
executes any slower than &fn() - haven't checked.
I'd imagine it is, but I wouldn't sweat an added indirection when
you're talking about a bytecode interpreter.
The other thing I find, with hashes and arrays and such, is that half
the time in perl I end up using references to those things stored in
scalars anyway. Particularly when I need nested structures.
Certainly, references to hashes especially are important, in
particular for supporting defstruct. But if you want to interact with
Perl builtins, being able to spread arrays is important. I guess you
don't need all 4 namespaces for that, it just makes the resulting Perl
less crazy-looking.
Oooh, just noticed this. I'm glad I didn't try to go that route, I
was happy to have all of Common Lisp at my disposal when writing my
compiler. You might want to reconsider this decision, if you find
yourself having implementation difficulties -- compilers are a lot
easier to write in big languages (like CL, or one of the big scheme
implementations' dialects with all the add-ons).
I'm not quite sure I understand this at the moment. I'll have to think
about it some more. If the generated perl looked like that wouldn't it
clash with a variable called 'a'? I know I'm probably being thick here.
The point is that a naive translation would be:
{ my $a1 = 0;
{ my $a2 = 100;
$a1 = $a2 + 100; # clash
{ my $a3 = "hi";
print $a3;
}
}
print $a1;
}
If you named $a1, $a2, and $a3 all just $a, it would work, except for
the line labeld "clash", which refers to an $a from two different
scoping levels. So you can name $a1 and $a3 plain old $a, and only
need to give $a2 a distinct name. In $a3's scope, it is the only $a
variable used.
- I'm not sure how you can get better undefined-function error
reporting if you use the scheme approach. If you use multiple
namespaces in your Lisp, the function namespace maps directly from
Lisp to Perl, so you get normal Perl error reporting.
I know, and it would seem the obvious thing to do wouldn't it? I still
like the single namespace though, but fear not - I thought of a solution
[me: looks up solution in files of notes about the program...]
Ah, here we go: I'm planning to modify the compiler to keep track of
lexical scope. That way, when it compiles a reference to an undefined
variable it should know and generate a warning about it. This may be
related to the gensym issue above. I guess generating symbols can be
done if I keep track of scope. I'll have to think about that some more.
Yeah, they're def related.
Incidentally, can you think of a good argument AGAINST the scheme single
namespace approach?
You get to it yourself in a second
One thing you might consider here is losing the Lisp1-ness, but
keeping the Scheme-like handling (normal evaluation) of the first
position in a form.
[snip]
That is a thought. I suppose it would make it play nicer with 'normal'
perl code. It would be particularly useful for using built in functions.
At the moment I have to 'declare' those:-
(<perl-sub> print)
which expands to a (defmacro ...)
Yeah, that's a benefit of recognizing at least the function and
variable namespaces. That way, you can easily use normal Perl
functions, and your functions aren't second-class citizens (eg, you
can write a module that Perl coders can use directly, normally).
I guess the first thing to do in any case is to extend the compilartion
functions so that they keep track of lexical scope.
That is the traditional thing to do when writing scheme compilers
--
/|_ .-----------------------.
,' .\ / | No to Imperialist war |
,--' _,' | Wage class war! |
/ / `-----------------------'
( -. |
| ) |
(`-. '--.)
`. )----'