Re: Designing Lisp from scratch
[email protected] Sun, 18 Mar 2007 22:30:59 EDT
| Newsgroups | gmane.comp.lang.lightweight |
|---|---|
| Message-ID | <[email protected]> |
I'm happy that you brought these things up, as it can gradually help me
sharpen my explanations in case I later want to write a formal paper about it.
And it can help me see what might be missing in what I've done.
I was hoping to checkmark each item you mentioned, but it turned out to be
more than I could chew in one sitting. I'm not a native Scheme / Lisp /
functional language programmer. I'll have to spend more time mulling over some of
those ideas. In any event, let me comment on what I can for now.
First though, some background info. What I implemented was a version of
Common Lisp, which I constructed gradually as I read through Colin Allen's Lisp
Primer tutorial found online at mypage.iu.edu/~colallen/lp (I included much,
but not everything there). I had previously read through other Lisp
documentation, which I also used as reference. I used the GNU Common Lisp
interpreter to compare results with my interpreter.
Why did I choose CL instead of Scheme? Well had I done Scheme, the question
might have been why I implemented Scheme instead of CL. I probably chose CL
because I found better tutorials for it, and figured that there might be
more CL practitioners than Schemers. Perhaps with the exception of
continuations, I think the differences between the two dialects are superficial enough
that anyone can easily modify my CL implementation and turn it into Scheme.
Scheme being minimalist and smaller than CL, I'd imagine that it might actually
be even easier to implement than CL.
There are various possible ways you could implement Lisp with uCalc.
However, I've chosen a way that would be easiest for me to quickly implement, and
easy for users unfamiliar with uCalc to follow. Efficiency and optimizations
were the very least of my concerns (though you wouldn't be able to tell if
you're only running snippets of code like those found in tutorials). On the
other hand my Basic implementation is more efficient, but I had to write a
separate file with a line-by-line explanation of the code to help people better
understand it.
The Language Builder is designed to be capable of executing code at maximal
speed. However, the actual language design implementations and optimizations
are left to the programmer.
> - LISP-style macro programming
This one is directly supported in my Lisp implementation. In fact, though
this might seem like one of the more challenging constructs, it turned out to
be a very straightforward thing to implement.
Notice that I said it's supported by my implementation of Lisp. The
Language Builder itself does not support LISP-style macro programming. Nor does it
support S-expressions, higher order functions, anonymous lambda functions,
etc... It only provides you with the building blocks that you can easily put
together to construct such abstractions.
> - generic programming
Directly supported. Looking this up in Wikipedia, I found there might be
several variants of meaning attached to this expression. So I'll discuss
several different ways in which I think uCalc supports generic programming.
It mentions how you can create new Forth compiler keywords and
implementations on the fly. I have a Forth implementation. And the whole Forth language,
including the "compiler keywords" (though mine is interpreted), is defined
on the fly. You can likewise continue to implement new keywords, either using
the conventional Forth syntax, now that the language is defined, or using the
same language builder methods that were used to create Forth (all still done
on the fly).
An example in Wikipedia is given of a template that swaps two variables of
any type that are passed by reference. As mentioned before, the language
builder doesn't have any "built-in" functions. But I have a library of common
methods to pick from so that you don't necessarily have to start from scratch.
One library method ("template") allows you to assign a value to a variable,
without knowing in advance what kind of type the variable has. The variable
argument is not passed by "reference" but by "handle". With a handle, not
just the variable's address, but also everything else associated with it is
accessible (its name, datatype etc...). This "template" doesn't know how to
actually assign a value. When you define a data type, you tell that type how to
assign data to it. So the variable assignment method simply relies on the
data assignment code that was defined for the given data type.
Something somewhat similar to the array example can be done as well. For
instance there's a uCalc "template" (again not "built-in" but defined in a
plain text code file) for defining arrays (I didn't include arrays in Lisp
though). This will work with almost any data type.
Parametric polymorphism is possible in this way: When you define a data
type, you define how it allocates, stores, retrieves data, etc... Your routine
will call the appropriate method for the data type of the argument without
having to know the details of how that method is implemented. Type safety can
be automatically enforced (or suppressed).
>- functional reactive programming
I looked at a paper by Ignatoff, Cooper, and Krishnamurthi, regarding
Functional Reactive languages, which also talks about FrTime. I got a sense that
it was a great challenge to expand a language like Scheme beyond its normal
syntactic boundaries to make it support abstractions for dealing with values
that change over time. I may completely be missing the boat, but from examples
like the ones dealing with seconds, it looked like it would not require any
special effort at all to implement this in uCalc. That's because uCalc does
not start with a Scheme syntax, or imperative style, or any particular
paradigm. It does not favor one style over another. The result is that it's very
easy to mix-and-match various paradigms that normally wouldn't be found in
the same language.
>- meta object protocols
This may not be exactly the same, but everything that you can define in
uCalc has a handle. And each item with a handle has properties that you can
inspect, and in many cases change. Depending on the type item, the properties
might for instance be the item's name, value, address, data type, syntax,
related items, thread, etc...
>- tail call optimization
I didn't find a way to implement this yet. However, I suspect that if I do,
it will not involve changing anything in the Language Builder itself.
Instead it would simply involve finding the right end-user code to do it.
>- continuations
I did not fully grasp the concept of continuations yet. It seems kind of
complicated and esoteric to me. But I suspect that if I do finally get it, it
would also involve applying the right code instead of modifying uCalc. And
of course, anyone reading this is welcome to download uCalc to see if they
could figure out a way to implement continuations.
Daniel Corbier
uCalc Language Builder
www.ucalc.com
In a message dated 3/13/07 6:36:38 PM Eastern Standard Time,
[email protected] writes:
> What do you guys think of this idea?
It depends on the details but in general I'm always in favor of
general purpose rather than special purpose tools. However, some
language concepts are harder to capture than others, and if they are
not built-in at the fundamental level, it may not be possible to
implement them later efficiently. Examples: Does your system directly
support or indirectly allow:
- tail call optimization
- continuations
- meta object protocols
- functional reactive programming
- generic programming
- LISP-style macro programming
If your system doesn't support efficiently implementing these
capabilities then it is not fully general purpose. Many people might
not care, but these are all areas of great interest to me personally,
so for example I could not use a language building tool that did not
support them. I suspect many people on this list would feel similarly
and not be interested until / unless some of these advanced features
become available.
A good rule of thumb is, can you implement Scheme, as opposed to just
LISP? A system that is the equal or a superset of Scheme's basic
features is interesting, and a system with less than that is not so
interesting. I speak only for language geeks -- the rest of the world
may have much use for systems that have capabilities similar to LISP;
see Python, Perl & JavaScript for successful examples of that.
CLOS, the LISP macro system, and FrTime are also interesting tests. A
system that can implement any of those also gets an "A" for
capability.
************************************** AOL now offers free email to everyone.
Find out more about what's free from AOL at http://www.aol.com.