Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

There aren't a lot of symbols to Lisp but there's plenty of syntax

Using Racket:

  (if bool then else) instead of (if bool then) or (if (bool then) (bool else))
  (if (> x y)
    (x)
    (y)) ;fails for numbers because (x) is considered a function call (even though 3 is an invalid identifier and thus can be assumed to be always be a number).
 (define (fun x y) (...)) instead of (define fun (x y) (...)) or (define ((fun (x y)) (...)))
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



Technically, this might be syntax, but as someone who is learning Racket (and programming) in the beginning stages, it's so much less syntax to remember then even python (underscore, double underscore, with, decorators, list comprehensions etc all have their own syntax nuances), the only syntax I see in Racket is the s-expression, the quote, and the dots. Everything else is just the flow of programming logic. It really does free my mind to work on the problem domain itself! Been enjoying SICP so much.


Racket doesn't get quite as bad (well it does but it tries to keep things looking like S-exps) but consider CL's Loop macro http://www.unixuser.org/~euske/doc/cl/loop.html loop is (from what I understand) idiomatic too. Yes it's a macro (so is (defun ...) though) but it's syntax a CLer needs to know in order to deal with CL in the wild. Format is famously even worse.


A lot of people abandon loop for precisely that reason (it's un-lispy) and use Iterate.

https://common-lisp.net/project/iterate/

Even the ITA/Google style guide says to avoid loop if possible:

https://google.github.io/styleguide/lispguide.xml#Iteration


But the ITERATE macro is syntax, too.

Almost every macro in Lisp provides syntax.


Yes, but I thought his point was more that whilst Lisp has a very easy, simple and regular syntax, ie. (func arg1 arg2 (func arg3)) and so on, it's less simple and regular when you get to the loop macro (loop arg keyword arg keyword...). Hence why I mentioned the Iterate library as something a lot of people use to get back to the regular syntactical appearance.

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.


> 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 ;)


It's debatable whether "simple and regular syntax" is a strength or a weakness. Lisp/Scheme might be too regular for their own good. Consider the following statements in Scheme, for instance:

    (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.


SBCL will warn or error at compile time on the first two, and there are similar issues to the third one in many languages; it's a semantics issue more than a syntactic issue.


An equivalent to iterate/loop where each compound form need be replaced by an anonymous function and each binding is replaced by a dictionary entry could be implemented completely as a function. Is this also new syntax?

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).


Even Racket says loops are unRacket like and so does R. I avoid loops at all cost and use list whenever possible.


Loop is idiomatic, but whether or not it is syntax is arguable, as it is implemented entirely as a macro.


I think you're conflating syntax with semantics.


I am not. Syntax is the structure, semantics the meaning (I mean more or less).

(def (fun x y) (...)) is syntactically different than (def fun (x y) (...)) even if they are semantically equivalent.


(3) vs 3 is a both really. In say smalltalk you can call 3 and it would return 3 because semantically it's an object where as in lisp it's not callable (even if in CL it may be represented as a CLOS object I don't know)

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 syntax is the same. Both are s-expressions. The difference is how a particular implementation interprets them. In this example, it would depend on the semantics of def.


That's only the syntax of s-expressions - a data format.

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.


That is interesting. I've always considered lisp in terms of denotational semantics. In fact, I wrote a toy lisp in which the complete grammar was basically

    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 ...)).


Lisp as the idea has no syntax. Racket is a dialect of that idea, and the authors have decided to add syntax.


Lisp "as the idea" is not a programming language. Racket is a language, Common Lisp* is a language. No one writes code in the IDEA of lisp, indeed no one can because no computer yet can pull instructions out of what ever aether contains platonic ideals.

* using SBCL: (defun foo (x y) (...)) instead of Racket (define (foo x y) (...)) is again an example of syntax.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: