Lisp is the only high-level programming language that has no syntax. In Lisp, s-expressions are used to encode both form (data structures) and function (algorithms) of computer programs. Since code and data are seen for what they are (two sides of the same coin) the distraction of a real PL syntax is eliminated, and the programmer is able to think more coherently.
Of course Lisp has syntax! Do you write a list as [1, 2, 3] or as (1 2 3)? Only the SYNTAX of the language can tell you.
I think we all know what you meant and that the way you said is a common way to say it, but being common doesn't make it correct. I wish people would rephrase that as "Lisp has a simple, fairly uniform syntax" or something like that. At any rate that's not the important point! What matters is the other thing you said: that programs in Lisp are represented in terms of the convenient, built-in data structures, the famous 'homoiconicity'.
Lisp has built-in syntax for example in the form of special operators.
LET is an example. LET provides bindings for variables:
LET
a list of bindings
a sequence of declarations
a sequence of expressions
(LET ((a 1)
(b 2)
c)
(declare (integer a))
(declare (type (integer 0 100) b)
(setq c (+ a b))
(expt c 2))
The EBNF syntax for LET is:
let ({var | (var [init-form])}*)
declaration*
form*
DECLARATION and FORM have more syntax.
If Lisp sees a LET form which does not use above syntax, then it is a syntax error. A compiler or interpreter will tell you that. The compiler will detect that at compile time.
The following forms are all errors:
(let a 10 (+ a 10))
(let (a 10) (+ a 10)) ; 10 is not an identifier
(LET (((A) 10)) (+ a 10)) ; (a) is not an identifier
(let ((a 10)) (+ a 10) (declare (integer a))) ; declaration at wrong place
(let ((a = 10)) (a + 10)) ; Lisp has no infix operators...
Forth is written as a syntax tree in exactly the manner of Lisp. There are two differences, neither of which affects the fact that you express the AST directly:
1. Lisp is written preorder; Forth is written postorder.
2. The number of children a node in your Lisp AST has is marked explicitly, by parentheses, whereas the number of children a node in your Forth AST has is defined externally.
There is no difference between a Lisp-style
(+ (* 3 5 8) (+ 4 1))
and a Forth-style
3 5 8 * * 4 1 + +
except that the * in Forth-style can't take a variable number of arguments. But if you added parens to Forth, it could:
> Lisp is the only high-level programming language that has no syntax.
Hogwash.
What's the difference between a list and a cons pair? That simple "." makes a HUGE world of difference when trying to parse S-expressions. That's syntax.
Why is there a difference between macros and reader macros? That's also syntax.
About as far as you can go is that "In Lisp, code and data have the same syntax." And even that is a bit dicey.
What is dicey about code and data having the same representation? You use the word 'syntax' rather than representation but s-expressions is not a syntax per se.
defun function-name argument-list declarations/documentation forms
Above is syntax.
An example of a function using a lot of syntax:
(defun foo (n &optional (a 10 a-p))
"This is the function FOO"
(declare (type (integer 0 *) n a))
(declare (ignore a a-p))
(loop for i from 0 below n by 10
sum i into s1
sum (expt i 2) into s2
finally (return (/ s1 s2))))
Lisp has complex argument lists with required, keyword and optional arguments.
It has syntax for a bunch of declarations.
It has macros like the LOOP macro which implement a lot of syntax. Actually the syntax of LOOP is quite long.
Well... But to be fair, LOOP is something of an oddity within Lisp... The Marmite (or Vegemite) of Lisp, due to exactly that: introducing a COBOL-like language for iterating.
PS: I like all your coments on Lisp, Rainer. Very informative.
(LOOP FOR X FROM M TO N DO (PRINT X) WHILE (PRIMEP X))
Warren's greater idea was to have a very forgiving syntax for Lisp, with spell checker and DWIM (do what I mean) support. Write expressions in different order, with spelling errors, etc. Lisp will figure out what you mean.
DEFINEQ((UNION (LAMBDA (X Y)
(IF ~X THEN Y
ELSEIF X:1 MEMBER Y THEN UNION X::1 Y
ELSE <X:1 !(UNION X::1 Y)>]
In MLISP:
EXPR UNION (X,Y)
IF ¬X THEN Y ELSE
IF X[1] ε Y THEN UNION(X↓1,Y)
ELSE X[1] CONS UNION(X↓1,Y);
In CGOL (Algol syntax on top of Lisp)
define x "UNION" y, 14, 13;
if not x then y
else if member(car x, y) then cdr x union y
else car x . cdr x union y <>
or CGOL with extended character sets:
define x "∪" y, 14, 13;
if ¬x then y else if αx ε y then βx ∪ y else αx . βx ∪ y <>
'Conversational' syntax elements were for example often used in some AI systems as user interfaces into knowledge based systems. Rules were often written in similar expressions, example from KEE:
(IF (THE SWITCH OF LIGHT IS ON)
(THE LOOK OF LAMP IS NO.LIGHT)
THEN (DELETE (THE STATUS OF LAMP IS WORKING))
(THE STATUS OF ROOM IS DARK))
Though I'd think the main purpose of LOOP is to have an example that Lisp can incorporate a wider range of embedded syntax variants and to make the language purists run away...
Perhaps, but there's no hard evidence that lack of syntax leads to better results. All else being equal, most programmers seem to prefer at least some syntax. Is a long s-expression containing multiple nested parentheses easy to think about?
Well, many languages like Ada/Pascal or even SQL try to reduce the number of parentheses/braces. But you can manipulate their AST in Lisp easily; that's what makes working with DSLs easy.
if foo.validate() {
println!("{} is the right answer", foo);
}
This has less parentheses (unless you count the placeholder in the format string). Putting the condition in parentheses like C and friends do is redundant if you use braces for the block anyway.
less parentheses, but not less bracket-like characters. If you count parens and curlies, it is exactly the same. Yours has 4 parens and 2 curlies (not including the format string), and the original lisp code has 6 parens.
Think about? Maybe, as it's completely unambiguous.
Edit? Oh hell yes. Once someone groks paredit (a weekend to get fluent), every other language is painful. It's because you're editing in terms of complete forms, rather than in units mismatched to the actual code.
Remember your first text editing experience? You probably spent a long time editing in terms of characters. Then remember what a revelation it was when you learned a programmers editor and started being able to manipulate larger portions of text such as words, lines, and even paragraphs?
Paredit is like that, but the next level, because you're working at the level of arbitrary syntactic forms.
I would heartily agree that some syntax is preferable to none ... when you're writing code in general. However, little or no syntax is a huge advantage when you're writing code that writes code. That's what makes Lisp so powerful.
Should have said "Lisp has no REAL syntax" and left the definition of REAL to further discussion. Since I did not do that, all comments here are kind of missing that subtle but important distinction.