Is it legal to call a C compiler written in C or a PHP interpreter written in PHP metacircular? Is this definition valid only for languages of a specific type, like Lisp? In short, what are the conditions that an interpreter should satisfy for being called Metacircular?
In practice, the difference is in the location where the preprocessor searches for the included file.
#include <filename> the preprocessor searches in an implementation dependent manner, normally in search directories pre-designated by the compiler/IDE. This method is normally used to include standard library header files.
#include "filename" the preprocessor searches first in the same directory as the file containing the directive, and then follows the search path used for the
#include <filename> form. This method is normally used to include programmer-defined header files.
A more complete description is available in the GCC documentation on search paths.
To give the short answer, macros are used for defining language syntax extensions to Common Lisp or Domain Specific Languages (DSLs). These languages are embedded right into the existing Lisp code. Now, the DSLs can have syntax similar to Lisp (like Peter Norvig's Prolog Interpreter for Common Lisp) or completely different (e.g. Infix Notation Math for Clojure).
Here is a more concrete example:
Python has list comprehensions built into the language. This gives a simple syntax for a common case. The line
divisibleByTwo = [x for x in range(10) if x % 2 == 0]
yields a list containing all even numbers between 0 and 9. Back in the Python 1.5 days there was no such syntax; you'd use something more like this:
divisibleByTwo =  for x in range( 10 ): if x % 2 == 0: divisibleByTwo.append( x )
These are both functionally equivalent. Let's invoke our suspension of disbelief and pretend Lisp has a very limited loop macro that just does iteration and no easy way to do the equivalent of list comprehensions.
In Lisp you could write the following. I should note this contrived example is picked to be identical to the Python code not a good example of Lisp code.
;; the following two functions just make equivalent of Python's range function ;; you can safely ignore them unless you are running this code (defun range-helper (x) (if (= x 0) (list x) (cons x (range-helper (- x 1))))) (defun range (x) (reverse (range-helper (- x 1)))) ;; equivalent to the python example: ;; define a variable (defvar divisibleByTwo nil) ;; loop from 0 upto and including 9 (loop for x in (range 10) ;; test for divisibility by two if (= (mod x 2) 0) ;; append to the list do (setq divisibleByTwo (append divisibleByTwo (list x))))
Before I go further, I should better explain what a macro is. It is a transformation performed on code by code. That is, a piece of code, read by the interpreter (or compiler), which takes in code as an argument, manipulates and the returns the result, which is then run in-place.
Of course that's a lot of typing and programmers are lazy. So we could define DSL for doing list comprehensions. In fact, we're using one macro already (the loop macro).
Lisp defines a couple of special syntax forms. The quote (
') indicates the next token is a literal. The quasiquote or backtick (
`) indicates the next token is a literal with escapes. Escapes are indicated by the comma operator. The literal
'(1 2 3) is the equivalent of Python's
[1, 2, 3]. You can assign it to another variable or use it in place. You can think of
`(1 2 ,x) as the equivalent of Python's
[1, 2, x] where
x is a variable previously defined. This list notation is part of the magic that goes into macros. The second part is the Lisp reader which intelligently substitutes macros for code but that is best illustrated below:
So we can define a macro called
lcomp (short for list comprehension). Its syntax will be exactly like the python that we used in the example
[x for x in range(10) if x % 2 == 0] -
(lcomp x for x in (range 10) if (= (% x 2) 0))
(defmacro lcomp (expression for var in list conditional conditional-test) ;; create a unique variable name for the result (let ((result (gensym))) ;; the arguments are really code so we can substitute them ;; store nil in the unique variable name generated above `(let ((,result nil)) ;; var is a variable name ;; list is the list literal we are suppose to iterate over (loop for ,var in ,list ;; conditional is if or unless ;; conditional-test is (= (mod x 2) 0) in our examples ,conditional ,conditional-test ;; and this is the action from the earlier lisp example ;; result = result + [x] in python do (setq ,result (append ,result (list ,expression)))) ;; return the result ,result)))
Now we can execute at the command line:
CL-USER> (lcomp x for x in (range 10) if (= (mod x 2) 0)) (0 2 4 6 8)
Pretty neat, huh? Now it doesn't stop there. You have a mechanism, or a paintbrush, if you like. You can have any syntax you could possibly want. Like Python or C#'s
with syntax. Or .NET's LINQ syntax. In end, this is what attracts people to Lisp - ultimate flexibility.
- When is assembly faster than C?
- Do I cast the result of malloc
- C++ – the effect of extern “C” in C++
- The difference between a definition and a declaration
- C++ – the “–>” operator in C/C++
- Sqlite – Improve INSERT-per-second performance of SQLite
- What does the ??!??! operator do in C
- Linux – “:-!!” in C code