https://common-lisp.net/project/iterate/
Even the ITA/Google style guide says to avoid loop if possible:
Almost every macro in Lisp provides syntax.
It's one of the strengths of Lisp imo; that you don't need to think much about how the parser is going to interpret your code (ie. missing semi-colons, whitespace, use curly brace here, square bracket there, etc.), just stick to (func arg1 arg2) and all you're left with is your own logic errors.
(func arg1 arg2 (func arg3))
That's the syntax of function calls.But Lisp has a few special forms and zillions of macros. Most of them are syntax.
Lisp has IF. What is the syntax of IF?
IF form then-form else-form+
Lisp has COND. What is the syntax of COND? cond {clause}*
clause::= (test-form form*)
List has DEFUN. What is the syntax of DEFUN? defun function-name lambda-list [[declaration* | documentation]] form*
Now what is the syntax for LAMBDA-LIST? lambda-list::= (var*
[&optional {var | (var [init-form [supplied-p-parameter]])}*]
[&rest var]
[&key {var | ({var | (keyword-name var)} [init-form [supplied-p-parameter]])}* [&allow-other-keys]]
[&aux {var | (var [init-form])}*])
and so on...> It's one of the strengths of Lisp imo; that you don't need to think much about how the parser is going to interpret your code (ie. missing semi-colons, whitespace, use curly brace here, square bracket there, etc.), just stick to (func arg1 arg2) and all you're left with is your own logic errors.
What you describe is just the data syntax for s-expressions. Not the syntax of the programming language Lisp.
Exactly. The data syntax if what most people worry about. The names of the verbs (funcs/methods/etc.) may change from language to language, but the data syntax is what trips people up. I think Lisp has one of the simplest and clearest. There are very few cases of "oh you can't write that there, only nouns are allowed in that position".
I agree with your point, but I think we're arguing slightly different points here ;)
(lambda x (+ x x))
(cond (> x 2) (+ x x))
(if (> x 2)
(do-this when-true)
(also-do-this when-true))
They are syntactically correct (technically), but they are probably not what you meant. So you still have to pause and ask yourself how cond works... except the parser will not help you.That is to say, a problem with s-expressions is that they are so regular that everything looks the same, and when everything looks the same, it can become an obstacle to learning. Mainstream languages are not very regular, but they are more mnemonic. I think Lisp works best for a very particular kind of mind, but that for most programmers its strengths are basically weaknesses.
(if (> x 2)
(do-this when-true)
(also-do-this when-true))
In some other language: x > 2 ? doThis(whenTrue) : alsoDoThisWhenTrue();
Same problem. Maybe even slightly worse. For example it could be: x > 2 ? doThis(whenTrue) ; alsoDoThisWhenTrue();
To spot the difference between a colon and the semicolon: tough.If not, how is the macro different other than implicitly changing the evaluation?
for a more simple example, why is the idiom CALL-WITH-FOO (implemented as a function) not syntax while WITH-FOO (implemented as a macro) is? What precisely is syntax is somewhat nebulous (if I use a regex library in C, have I added syntax to the language? Regexes certainly are syntax, despite being wrapped in a C string).
(def (fun x y) (...)) is syntactically different than (def fun (x y) (...)) even if they are semantically equivalent.
syntactical ( ) isn't actually a procedure call we can see this in (define (id x y) (..)) or (let ((x 3)) ...) in the theoretically pure Lisp semantically it's just a leaf in the tree but as part of an if-block in a real language it gets treated as procedure call even if it makes no sense.
The Lisp syntax is defined on top of s-expressions.
For example Common Lisp has a CASE operator. That's the EBNF syntax:
case keyform {normal-clause}* [otherwise-clause] => result*
normal-clause::= (keys form*)
otherwise-clause::= ({otherwise | t} form*)
An example: (case id
(10 (foo))
(20 (foo) (bar))
(otherwise (baz)))
The expressions are written using s-expressions as data. But still there is structure in those s-expressions, described by the EBNF syntax of CASE.Every special operator and every macro provides syntax. Since users can write macros themselves, everybody can extend the syntax. On top of s-expressions.
list -> ({symbol | number | string | list}*)
and then it was up to the interpreter to decide the meaning of special forms. (I say "basically" because there was also desugaring of '(...) to (quote ...)).* using SBCL: (defun foo (x y) (...)) instead of Racket (define (foo x y) (...)) is again an example of syntax.
Using Racket:
That's syntax.Just because I'm not using {}'s here and infix there doesn't make it any less syntax. That's just the two most basic forms too; bring in loop? forget about it. This also ignores things like '(@,) or (x . y) but I'm not a lisper so I don't know how often that actually comes up