McCarthy's original Lisp and some number of incarnations thereafter did not have a macro facility like we now have in Common Lisp, Clojure, Scheme, etc... This I know.
However, it is unclear to me exactly how macros came to be, what implementation(s) had them first, and what motivated them. References to papers and source would be ideal if you please.
From The Evolution of Lisp (PDF):
Macros appear to have been introduced into Lisp by Timothy P. Hart in 1963 in a short MIT AI Memo [Hart, 1963]
See:
AIM-57 Author[s]: Timothy P. Hart
MACRO Definitions for LISP
October 1963
ftp://publications.ai.mit.edu/ai-publications/0-499/AIM-057.ps
ftp://publications.ai.mit.edu/ai-publications/pdf/AIM-057.pdf
In LISP 1.5 special forms are used for
three logically separate purposes: a)
to reach the alist, b) to allow
functions to have an indefinite number
of arguments, and c) to keep arguments
from being evaluated. New LISP
interpreters can easily satisfy need
(a) by making the alist a SPECIAL-type
or APVAL-type entity. Uses (b) and (c)
can be replaced by incorporating a
MACRO instruction expander in define.
I am proposing such an expander.
John Shutt's PhD thesis first part concerns the history of lisps, including the introduction of macros, I believe. It's not entirely clear to me on reading, but it seems that he claims that macros are more-or-less identified with an "extensible languages" movement (which is independent of lisp), and that M.D. McIlroy's 1960 paper, "Macro Extension Instructions of Compiler Languages", was foundational to the extensible languages movement... implying that macros were introduced to the academic literature in 1960.
Related
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 6 years ago.
Improve this question
There are Clojure, Scheme, etc. which are dialects of LISP, you can find a lot more at this SO question on which dialect is the best.
My question is pretty basic - what is a LISP dialect? Languages like C, C++, Java, JavaScript, PHP share similar syntax, but are different languages. Poeple don't call them different dialects of ALGOL. So why do people call these dialects of LISP? What does that actualy mean?
There are just a few syntaxes around. We have Algol which coveres almost all the programming languages like SQL, Python, Pascal, PHP, and JavaScript. Some might say most of these are C, or B and they are right since these were the first to replace the typical begin with {. Looking at your profile you know mostly algol dialects and when you learned the last one it probably was simple since you already knew much from the knowledge of their sibling languages. You didn't learn a new language but a variant of one you already knew.
Lisp came in the late 50s and it had symbols and lists. It's syntax was not based on Fortran, that was the language of choice at the time. The original paper expressed eval using a few primitives. You can read about this in Paul Grahams excellent essay. If you know one dialect it's as easy to learn another in the same manner as with algol dialects. Trying to learn a lisp dialect by assimilating algol was very frustrating for me so I know this by experience.
Wikipedia has an excellent programming language tree you can browse. Like in natural language you have crazy languages like Finish that is not where to be found on the indieuropean language tree. You have such islands in programming languages as well. Lisp and Algol are truely different worlds even with some influenced over the decades.
As to the answer of what is needed for it to be a lisp dialect it's a little hazy, but I would include all languages that has one of these features:
Fully parenthesized polish prefix notation. (S-expressions)
cons,car,cdr and a symbol type with functions being first class citizens. eg. you can create mapcar (map in scheme)
Of course a undeniable lisp dialect would have both of these, but I would consider every language that only has one as lisp as well.
Sassy is intel assembly with better (lisp) syntax. It can perhaps expand macros and use the features of Scheme so it's a lisp but its restricted so not all would see it as a lisp dialect.
The creator of JavaScript, Brendan Eich, originally wanted to make a Scheme dialect. JavaScript is very close to be a Lisp but I still don't consider it a lisp since it has neither of my lisp feature sets. If they had made a singly linked lists a part of the spec I would have considered calling it a Lisp dialect with very bad looking syntax. Other people might include JS as a lisp.
I suggest that you start with the wiki, which says
In the Lisp world, most languages that use basic S-expression syntax and Lisp-like semantics are considered Lisp dialects, although they vary wildly, as do, say, Racket and Clojure.
I would say that a dialect of Lisp must subscribe to the most fundamental Lisp idea, specifically, easy tasks should be easy, hard tasks should be possible.
This often implies that the language should be extensible, IOW, it should grow to meet your needs. This hints in the direction of macros which allow one to extend the language syntax. This, in turn, requires that the original syntax should be relatively simple, IOW, probably, Sexp-based.
So, to me, the hallmarks of a Lisp dialect are
a powerful macro facility (IOW, the full language is available for code transformation at compile time) and
a simple syntax.
PS. Note that, according to some, Scheme is a dialect of Algol, so this is not a rigorous notion.
defstruct is not supported in ClojureScript - it would appear to be by design. Now it may be that this is effectively a deprecated part of the Clojure language, and the designers of ClojureScript were just hoping everyone had moved on. (But this is my speculation).
My question is: What was the reasoning behind ClojureScript not needing Clojure's defstruct?
defstruct is effectively deprecated in the language, in favor of defrecord. We are supposed to move on in (JVM-based) Clojure, so I would expect Clojurescript to be the same. See the following:
Clojure: data structures: "Note: Most uses of StructMaps would now be better served by records."
ClojureDocs: defstruct comment by steveminer: "Structs are obsolete. Use records instead. See defrecord."
The forthcoming The Joy of Clojure, 2nd ed. (prerelease V9 edition) by Fogus and Houser says "With the advent of defrecord, the need for structs has been nearly eliminated, and therefore structs aren’t covered in this book." (p. 322)
Also note that Programming Clojure, 2nd ed. by Halloway and Bedra covers defrecord but not defstruct (although there are some passing mentions of structures--maybe accidentally left from the 1st ed.).
I guess all the cool people are using defrecord these days. :-)
Alex Miller's answer to "Where should I use defrecord in clojure?" has a nice discussion of advantages (and disadvantages) of defrecord, although he's not, primarily, comparing it with defstruct.
I know they are dialects of the same family of language called lisp, but what exactly are the differences? Could you give an overview, if possible, covering topics such as syntax, characteristics, features and resources.
They all have a lot in common:
Dynamic languages
Strongly typed
Compiled
Lisp-style syntax, i.e. code is written as a Lisp data structures (forms) with the most common pattern being function calls like: (function-name arg1 arg2)
Powerful macro systems that allow you to treat code as data and generate arbitrary code at runtime (often used to either "extend the language" with new syntax or create DSLs)
Often used in functional programming style, although have the ability to accommodate other paradigms
Emphasis in interactive development with a REPL (i.e. you interactively develop in a running instance of the code)
Common Lisp distinctive features:
A powerful OOP subsystem (Common Lisp Object System)
Probably the best compiler (Common Lisp is the fastest Lisp according to http://benchmarksgame.alioth.debian.org/u64q/which-programs-are-fastest.html although there isn't much in it.....)
Clojure distinctive features:
Largest library ecosystem, since you can directly use any Java libraries
Vectors [] and maps {} used as standard in addition to the standard lists () - in addition to the general usefullness of vectors and maps some believe this is a innovation which makes generally more readable
Greater emphasis on immutability and lazy functional programming, somewhat inspired by Haskell
Strong concurrency capabilities supported by software transactional memory at the language level (worth watching: http://www.infoq.com/presentations/Value-Identity-State-Rich-Hickey)
Scheme distinctive features:
Arguably the simplest and easiest to learn Lisp
Hygienic macros (see http://en.wikipedia.org/wiki/Hygienic_macro) - elegantly avoids the problems with accidental symbol capture in macro expansions
The people above missed a few things
Common Lisp has vectors and hash tables as well. The difference is that Common Lisp uses #() for vectors and no syntax for hash tables. Scheme has vectors, I believe
Common Lisp has reader macros, which allow you to use new brackets (as does Racket, a descendant of Scheme).
Scheme and Clojure have hygienic macros, as opposed to Common Lisp's unhygienic ones
All of the languages are either modern or have extensive renovation projects. Common Lisp has gotten extensive libraries in the past five years (thanks mostly to Quicklisp), Scheme has some modern implementations (Racket, Chicken, Chez Scheme, etc.), and Clojure was created relatively recently
Common Lisp has a built-in OO system, though it's quite different from other OO systems you might have used. Notably, it is not enforced--you don't have to write OO code.
The languages have somewhat different design philosophies. Scheme was designed as a minimal dialect for understanding the Actor Model; it later became used for pedagogy. Common Lisp was designed to unify the myriad Lisp dialects that had sprung up. Clojure was designed for concurrency. As a result, Scheme has a reputation of being minimal and elegant, Common Lisp of being powerful and paradigm-agnostic (functional, OO, whatever), and Clojure of favoring functional programming.
Don't forget about Lisp-1 and Lisp-2 differences.
Scheme and Clojure are Lisp-1:
That means both variables and functions names resides in same namespace.
Common Lisp is Lisp-2:
Function and variables has different namespaces (in fact, CL has many namespaces).
Gimp is written in Scheme :)
In fact allot of software some folks think might be written in C++ was probably done under the Lisp umbrella, its hard to pick out the golden apples out of the bunch. The fact is C++ was not always popular, it only seems to be popular today because of a history of updates. For the lesser half of the century C++ didn't even utilize multithreading, it was where Python is today a cesspool of useless untested buggy glue code. Fasterforward a little and now we are seeing a rise in functional programming, its more like adapt or die. I think Java has it right as far as the adapt part is concerned.
Scheme was designed to simplify the Lisp language, that was its only intent except it never really caught on. I think Clojure does something similar its meant to simplify Scheme for the JVM nothing more. Its just like every other JVM language just there to inflate the user experience, only to simplify writting boilerplate in Java land.
I want to learn new language and I thought to start with Lisp. I want to know if I learn Lisp do I also know Clojure ( with minimal effort ), is there big syntax differences between Lisp and Clojure ?
There are not big syntax differences (mostly because Lisp family languages have almost no syntax), but there are certainly differences in other areas. Clojure has a lot of modern programming features particularly suited to high scalability (actors, references, etc) that are not present as such in a "classic" Lisp (such as Common Lisp).
Clojure is an active, well supported dialect of Lisp. If you want to learn a Lisp, you can't really go wrong with Clojure.
You may find more information in the answers to Which Lisp should I learn? .
90% of what you learn while studying your first Lisp will carry over to your next.
I think it's fair to say that if you learn the principles of LISP you will also know the principles of Clojure and vice-versa. They are all rooted in the same philosophy, emphasising things such as:
Code is data. Macros are just normal functions that manipulate code.
Use of S-expressions to represent data and code.
The concept of a list / sequence as a fundamental structure.
Functional programming with first-class functions.
Apart from that, there are lots of differences in syntax, libraries, runtime environments etc. The difference in my view is probably about the same as C# vs. C++ - if you know one well, then the core concepts will be familiar but there are still a lot of fundamental differences.
See this list of ways that Clojure is different from other Lisps
I'm assuming by Lisp you mean Common Lisp, since 'Lisp' itself is more of a family of languages (that includes Clojure) than a single specific language.
There are some syntactical changes in that Clojure was intended to be a more modern Lisp. For instance you can create vectors with []s, maps with {}s, which are not part of Common Lisp. And of course the Java interop inevitably becomes a significant part of Clojure.
Clojure uses vectors as lambda parameters (arguments values), but you can use a macro to write versions of defun and lambda in Common lisp that will look similar . Clojure also has access to Java Object methods and fields using a period (i.e. ".") and the name of the method or field which looks like a normal function call.
(.toString 10) - will call the method toString on number 10 but .toString is not a function. if you try to check the value of .toString it throws an exception that .toString is not a defined symbol.
And also with quasi-quotation (mostly in macros) instead of using a coma for unquote as in Common lisp, Clojure use a tilde.
I find myself attached to a project to integerate an interpreter into an existing application. The language to be interpreted is a derivative of Lisp, with application-specific builtins. Individual 'programs' will be run batch-style in the application.
I'm surprised that over the years I've written a couple of compilers, and several data-language translators/parsers, but I've never actually written an interpreter before. The prototype is pretty far along, implemented as a syntax tree walker, in C++. I can probably influence the architecture beyond the prototype, but not the implementation language (C++). So, constraints:
implementation will be in C++
parsing will probably be handled with a yacc/bison grammar (it is now)
suggestions of full VM/Interpreter ecologies like NekoVM and LLVM are probably not practical for this project. Self-contained is better, even if this sounds like NIH.
What I'm really looking for is reading material on the fundamentals of implementing interpreters. I did some browsing of SO, and another site known as Lambda the Ultimate, though they are more oriented toward programming language theory.
Some of the tidbits I've gathered so far:
Lisp in Small Pieces, by Christian Queinnec. The person recommending it said it "goes from the trivial interpreter to more advanced techniques and finishes presenting bytecode and 'Scheme to C' compilers."
NekoVM. As I've mentioned above, I doubt that we'd be allowed to incorporate an entire VM framework to support this project.
Structure and Interpretation of Computer Programs. Originally I suggested that this might be overkill, but having worked through a healthy chunk, I agree with #JBF. Very informative, and mind-expanding.
On Lisp by Paul Graham. I've read this, and while it is an informative introduction to Lisp principles, is not enough to jump-start constructing an interpreter.
Parrot Implementation. This seems like a fun read. Not sure it will provide me with the fundamentals.
Scheme from Scratch. Peter Michaux is attacking various implementations of Scheme, from a quick-and-dirty Scheme interpreter written in C (for use as a bootstrap in later projects) to compiled Scheme code. Very interesting so far.
Language Implementation Patterns: Create Your Own Domain-Specific and General Programming Languages, recommended in the comment thread for Books On Creating Interpreted Languages. The book contains two chapters devoted to the practice of building interpreters, so I'm adding it to my reading queue.
New (and yet Old, i.e. 1979): Writing Interactive Compilers and Interpreters by P. J. Brown. This is long out of print, but is interesting in providing an outline of the various tasks associated with the implementation of a Basic interpreter. I've seen mixed reviews for this one but as it is cheap (I have it on order used for around $3.50) I'll give it a spin.
So how about it? Is there a good book that takes the neophyte by the hand and shows how to build an interpreter in C/C++ for a Lisp-like language? Do you have a preference for syntax-tree walkers or bytecode interpreters?
To answer #JBF:
the current prototype is an interpreter, and it makes sense to me as we're accepting a path to an arbitrary code file and executing it in our application environment. The builtins are used to affect our in-memory data representation.
it should not be hideously slow. The current tree walker seems acceptable.
The language is based on Lisp, but is not Lisp, so no standards compliance required.
As mentioned above, it's unlikely that we'll be allowed to add a full external VM/interpreter project to solve this problem.
To the other posters, I'll be checking out your citations as well. Thanks, all!
Short answer:
The fundamental reading list for a lisp interpreter is SICP. I would not at all call it overkill, if you feel you are overqualified for the first parts of the book jump to chapter 4 and start interpreting away (although I feel this would be a loss since chapters 1-3 really are that good!).
Add LISP in Small Pieces (LISP from now on), chapters 1-3. Especially chapter 3 if you need to implement any non-trivial control forms.
See this post by Jens Axel Søgaard on a minimal self-hosting Scheme: http://www.scheme.dk/blog/2006/12/self-evaluating-evaluator.html .
A slightly longer answer:
It is hard to give advice without knowing what you require from your interpreter.
does it really really need to be an interpreter, or do you actually need to be able to execute lisp code?
does it need to be fast?
does it need standards compliance? Common Lisp? R5RS? R6RS? Any SFRIs you need?
If you need anything more fancy than a simple syntax tree walker I would strongly recommend embedding a fast scheme subsystem. Gambit scheme comes to mind: http://dynamo.iro.umontreal.ca/~gambit/wiki/index.php/Main_Page .
If that is not an option chapter 5 in SICP and chapters 5-- in LISP target compilation for faster execution.
For faster interpretation I would take a look at the most recent JavaScript interpreters/compilers. There seem to be a lot of thought going into fast JavaScript execution, and you can probably learn from them. V8 cites two important papers: http://code.google.com/apis/v8/design.html and squirrelfish cites a couple: http://webkit.org/blog/189/announcing-squirrelfish/ .
There is also the canonical scheme papers: http://library.readscheme.org/page1.html for the RABBIT compiler.
If I engage in a bit of premature speculation, memory management might be the tough nut to crack. Nils M Holm has published a book "Scheme 9 from empty space" http://www.t3x.org/s9fes/ which includes a simple stop-the-world mark and sweep garbage collector. Source included.
John Rose (of newer JVM fame) has written a paper on integrating Scheme to C: http://library.readscheme.org/servlets/cite.ss?pattern=AcmDL-Ros-92 .
Yes on SICP.
I've done this task several times and here's what I'd do if I were you:
Design your memory model first. You'll want a GC system of some kind. It's WAAAAY easier to do this first than to bolt it on later.
Design your data structures. In my implementations, I've had a basic cons box with a number of base types: atom, string, number, list, bool, primitive-function.
Design your VM and be sure to keep the API clean. My last implementation had this as a top-level API (forgive the formatting - SO is pooching my preview)
ConsBoxFactory &GetConsBoxFactory() { return mConsFactory; }
AtomFactory &GetAtomFactory() { return mAtomFactory; }
Environment &GetEnvironment() { return mEnvironment; }
t_ConsBox *Read(iostream &stm);
t_ConsBox *Eval(t_ConsBox *box);
void Print(basic_ostream<char> &stm, t_ConsBox *box);
void RunProgram(char *program);
void RunProgram(iostream &stm);
RunProgram isn't needed - it's implemented in terms of Read, Eval, and Print. REPL is a common pattern for interpreters, especially LISP.
A ConsBoxFactory is available to make new cons boxes and to operate on them. An AtomFactory is used so that equivalent symbolic atoms map to exactly one object. An Environment is used to maintain the binding of symbols to cons boxes.
Most of your work should go into these three steps. Then you will find that your client code and support code starts to look very much like LISP too:
t_ConsBox *ConsBoxFactory::Cadr(t_ConsBox *list)
{
return Car(Cdr(list));
}
You can write the parser in yacc/lex, but why bother? Lisp is an incredibly simple grammar and scanner/recursive-descent parser pair for it is about two hours of work. The worst part is writing predicates to identify the tokens (ie, IsString, IsNumber, IsQuotedExpr, etc) and then writing routines to convert the tokens into cons boxes.
Make it easy to write glue into and out of C code and make it easy to debug issues when things go wrong.
The Kamin Interpreters from Samuel Kamin's book Programming Languages, An Interpreter-Based Approach, translated to C++ by Timothy Budd. I'm not sure how useful the bare source code will be, as it was meant to go with the book, but it's a fine book that covers the basics of implementing Lisp in a lower-level language, including garbage collection, etc. (That's not the focus of the book, which is programming languages in general, but it is covered.)
Lisp in Small Pieces goes into more depth, but that's both good and bad for your case. There's a lot of material on compiling and such that won't be relevant to you, and its simpler interpreters are in Scheme, not C++.
SICP is good, definitely. Not overkill, but of course writing interpreters is only a small fraction of the book.
The JScheme suggestion is a good one, too (and it incorporates some code by me), but won't help you with things like GC.
I might flesh this out with more suggestions later.
Edit: A few people have said they learned from my awklisp. This is admittedly kind of a weird suggestion, but it's very small, readable, actually usable, and unlike other tiny-yet-readable toy Lisps it implements its own garbage collector and data representation instead of relying on an underlying high-level implementation language to provide them.
Check out JScheme from Peter Norvig. I found this amazingly simple to understand and port to C++. Uh, dunno about using scheme as a scripting language though - teaching it to jnrs is cumbersome and feels dated (helloooo 1980's).
I would like to extend my recommendation for Programming Languages: Application and Interpretation. If you want to write an interpreter, that book takes you there in a very short path. If you read through writing the code you read and doing the exercise you end up with a bunch of similar interpreters but different (one is eager, the other is lazy, one is dynamic, the other has some typing, one has dynamic scope, the other has lexical scope, etc).