I do not understand the appeal of non-LISPy languages. I get that most people are used to reading it and that they are efficent, but I believe the developer (of the compiler in this case) should serve the convenience of the user, not the other way around.

Writing code like this is combersome and unnecessarily symbol heavy, and reading it isn't really nice as well.

I'd rather have the language add those extra parens into the parser than have me stare down these endless semi-colon, linebreaks or indentation. Parsing something Lisp-like is not that, hard, trust me, I've done it.

This doesn't really resonate with people though, as most people are more familiar with C-style notation. Also:

>Writing code like this is combersome and unnecessarily symbol heavy

Does not make sense in this context, as it mainly applies to Lisp-like languages that uses parentheses heavily.

>Does not make sense in this context, as it mainly applies to Lisp-like languages that uses parentheses heavily.

I had read, some years back, that someone did an actual calculation / demonstration that showed that the number of symbol / punctuation characters in Lisp is actually less than in C-based languages, for a block of code with equal functionality in both languages.

I don't have the reference handy. Someone here may know of it, and post it.

I never got people’s objections to the parentheses when the bottom of most js/ts files is a soup of three different flavors of closing bracket. Even more “fun” in languages like PHP that make you sprinkle ceremonial semicolons into some parts to satisfy the compiler. Hunting for the right brace is tedious, whereas in a lisp I just bounce on close paren til the open paren highlight is where I want it.

It's obvious to anyone who is familiar with both.

    (f x y)
vs

    f(x, y);
Note the extra comma and semicolon. The only place this breaks down is for simple arithmetic expressions like (+ a b) vs a + b, which is trivial enough to ignore (and also goes back in favor of Lisp when you start having more operands).

As someone who likes lisps, visual separation is helpful. I tend to find complicated Lisp code just blends together into syntax soup

How would you write this in Lisp without introducing a bunch of parens? `if (0 <= x + m && x + m <= n) {…}`

I’m not a Lisp hater, but there’s a reason people make this criticism. I think most people find the infix version easier to read.

    (if (<= 0 (+ x m) n) ...)
There is one additional set of parentheses due to the simple addition, which I already mentioned.

I unwittingly chose an example that allowed you to write fewer s-expressions in Lisp… touché.

I've been working on this for TXR Lisp. The next, release 300, will support infix.

The core expression in your example expression will parse as you have written it. Except we have to add ifx:

  1> (ifx (if (0 <= x + m && x + m <= n) (prinl 'do-this)))
  ** expr-1:1: warning: unbound variable x
  ** expr-1:1: warning: unbound variable m
  ** expr-1:1: warning: unbound variable x
  ** expr-1:1: warning: unbound variable m
  ** expr-1:1: warning: unbound variable n
  ** expr-1:1: unbound variable x
Though it doesn't work since it's not a complete example with defined variables, we can quote it and expand it to see what the expansion looks like, which answers your question of how you write it one underlying Lisp:

  1> (expand '(ifx (if (0 <= x + m && x + m <= n) (prinl 'do-this))))
  (if (and (<= 0 (+ x m))
        (<= (+ x m) n))
    (prinl 'do-this))
The ifx macro deosn't have to be used for every expression. Inside ifx, infix expressions are detected at any nesting depth. You can put it around an entire file:

  (ifx
    (defstruct user ()
      id name)

    (defun add (x y) (x + y))

    ...)
Autodetection of infix add some complexity and overhead to the code walking process that expands macros (not to mention that it's newly introduced) so we wouldn't want to have it globally enabled everywhere, all the time.

It's a compromise; infix syntax in the context of Lisp is just something we can support for a specific benefit in specific use case scenarios. It's mainly for our colleagues who find it a barrier not to be able to use infix.

In this particular infix implementation, a full infix expression not contained inside another infix expression is still parenthesized (because it is a compound form, represented as a list). You can see from the following large exmaple that it still looks like LIsp; it is a compromise.

I took an example FFT routine from the book Numerical Recipes in C and transliterated it, to get a feel for what it's like to write a realistic numerical routine that contains imperative programming "warts" like using assignments to initialize variables and such:

  (defun fft (data nn isign)
    (ifx
      (let (n nmax m j istep i
            wtemp wpr wpi wr wi theta
            tempr tempi)
        (n := nn << 1)
        (j := 1)
        (for ((i 1)) ((i < n)) ((i += 2))
          (when (j > i)
            (swap (data[j]) (data[i]))
            (swap (data[j + 1]) (data[i + 1])))
          (m := nn)
          (while (m >= 2 && j > m)
            (j -= m)
            (m >>= 1))
          (j += m))
        (nmax := 2)
        (while (n > nmax)
          (istep := nmax << 1)
          (theta := isign * ((2 * %pi%) / nmax))
          (wtemp := sin 0.5 * theta)
          (wpr := - 2.0 * wtemp * wtemp)
          (wpi := sin theta)
          (wr := 1.0)
          (wi := 0.0)
          (for ((m 1)) ((m < nmax)) ((m += 2))
            (for ((i m)) ((i <= n)) ((i += istep))
              (j := i + nmax)
              (tempr := wr * data[j] - wi * data[j + 1])
              (tempi := wr * data[j + 1] + wi * data[j])
              (data[j] := data[i] - tempr)
              (data[j + 1] := data[i + 1] - tempi)
              (data[i] += tempr)
              (data[i + 1] += tempi))
            (wr := (wtemp := wr) * wpr - wi * wpi + wr)
            (wi := wi * wpr + wtemp * wpi + wi))
          (nmax := istep)))))
It was very easy to transliterate the C code into the above, because of the infix. The remaining outer parentheses are trivial.

A smaller example is a quadratic roots calculation, from the test suite. This one has the ifx outside the defun:

  (ifx
    (defun quadratic-roots (a b c)
      (let ((d (sqrt b * b - 4 * a * c)))
        (list ((- b + d) / 2 * a)
              ((- b - d) / 2 * a)))))
sqrt is a function, but treated as a prefix operator with a low precedence so parentheses are not required.

It is only function calling that needs (,); in C and () in Lisp. Which is half as many characters, but much much much noisy since:

    - it is used everywhere
    - carries very little information
Look at the example on the Janet page transcribed to Python syntax [0]. Several differences:

    - in Janet nearly every line starts and ends with ( and ), which is just noise
    - in Janet there are several ))))
    - in Janet there is no special syntax for: function definition, variable definition, collections, statements
    - while Python is the opposite, it reads like a mix of English and Mathematics. Also it has special syntax for the ~5 things that you can do with the language, so you can just look at the Python code from far, don't read it, and you'll have a clue what's going on. It is also helpful when you search for something with your eyes. Also nested parentheses are different shaped parentheses, so you know which ones match.
Also in theory you could manipulate Python AST the same way you do in Lisps both in your editor and both at program-level. In practice you can't do that.

[0] : https://news.ycombinator.com/item?id=34846516

Ok, let's compare looping

    for (int i = 0; i < 5; i++) {
        printf("%d\n", i);
    }
vs

    (loop for i from 0 below 5
          do (format t "~A~%" i))
C has the same number of parentheses and also has curly brackets. C additionally has a bunch of semicolons and a comma not present in the Lisp version. The C version is also omitting the required function encapsulation to actually run this, while the Lisp version can be run as a top level expression.

The comparison really isn't even close. If you really want, you can always put the trailing )) on new lines like people do with the trailing }}}} for their nested if in a for in a method in a class in C-like languages. The Lisp community has just decided that putting single characters on new lines like that is needlessly noisy and emphasizes characters that are easily ignored by humans and instead manipulated using structural editing.

> The comparison really isn't even close.

IMO it's close. Lisp isn't much worse than other languages. Tho it needs special syntax for some common constructs. It helps the human.

Regarding the for loop, if you only loop one statement, you do

    for (int i = 0; i < 5; i++) printf("%d\n", i);
If you loop several statements, you do

  (loop for i from 0 below 5
        do (progn
           (format t "~A~%" i)
           (format t "~A~%" i)))
again, lisp lacks the syntax to group several statements together. In C it ends with );} , indicating a function call inside a control flow or a block. In lisp ))) can be anything from function definition to assigning variables or arrays/collections or anything.

Yeah was going to change that part too for something like "Writing code like this is verbose and spans too many lines", but then I just thought it'd be better if it sounded more like the parent comment.

And I understand it doesn't resonate with most, I just wanted to highlight how the initial parent comment was very subjective and not very substantive, some people didn't take the joke so well, I guess it could've sounded a bit passive aggressive. I personally enjoy both C-like and Lisp-like syntaxes and languages, I do have a sweet spot for Forth tho.

But back on topic, Fennel is a great language, working with Love and Fennel is really nice. And if the parentheses can seem off-putting for some, I'd highly encourage to give it a shot as you can quickly get past it and see how comfy it feels to have your statements properly demarkated.

S-expr shine the most when working with XML-like structure. Spinneret[1] was the most fun I ever had working with HTML, every other templating engine feels subpar now that I have tasted that sweet nectar..

[1] https://github.com/ruricolist/spinneret

It's your comment that seems to add the least, because the majority agree with the OP. The point is that ergonomics is not as good, of course there are contrary opinions. The existence of a contrary and minority opinion doesn't detract from the point.

>> as it mainly applies to Lisp-like languages that uses parentheses heavily.

This is so wrong. Lisp does not use parentheses heavily. It doesent even use more parens than any C like language. I just dont understand the fixation with parentheses. The power of lisps comes from the fact that everything is an expression. Someone can correct me if I am wrong, since I only have experience with functional lisp Clojure, but I believe other lisps are more or less similar.

So if everything can be evaluated, then you can have a really great REPL experience. You can be inside your favorite editor and have the tightest feedback loop possible. So the absence of statements is actually a great feature of the language which improves ergonomics.

The anti parentheses argument is usually just a straw that people grasp, who have no experience with writing code in lispy languages. A quick superficial jab at something they do not know well, so that they can go on with their day, without having to deal with learning a new thing, that might change their whole view of programming.

Plus, don't forget the secret sauce of Lisp syntax: same number of parentheses, with none of the commas. Nor the semicolons. Nor the brackets. Nor the braces.

[dead]

I just don't understand the fixation with REPL. How do you use it? It sounds like you write code as black box then run it in REPL to see what it does because you don't understand it by yourself.

> I just don't understand the fixation with REPL

Perhaps because maybe you just haven't used one? I'm not talking about "a REPL" in langs like Python, where you typically have to type stuff into it. Lisp REPLs allow evaluating code directly in the source buffer, by sending it into the REPL. That REPL can be remote. Like seriously remote - NASA once did it on a spacecraft 150 million miles away from Earth. We run ours in a kubernetes cluster. Lisp REPL allows you to evaluate specific expressions, functions, or regions directly from where you are. Without saving, linting, linking, compiling, etc.

> because you don't understand it by yourself.

REPL is not about "understanding your code", it's about interactive development and exploration - it allows you to test your ideas and assumptions in real-time. Imagine being able to send http request, pull some good chunk of data, and then sort it, group it, slice it, dice it, filter it, visualize it - do whatever you want to do with it, directly from your editor. It's incredibly empowering and extremely liberating.

The only downsides - after getting used to that, using non-lispy languages sucks all the joy out of programming and you also have to explain to people what it is like.

It's like moving to an island where people have never discovered salt, pepper, and other spices, and though their cuisine looks beautiful - you just can't describe to them what they all are missing. Some even may say - "Hey, I've tried pepper once - but I don't understand your fixation with it" and you'd be like: "have you ever tried putting it into your food?"

You check assumptions about dynamic types this way? To see what the function even returns in the first place. Browser console has a similar function: you type a function invocation, run it, then the returned value is presented as a tree for inspection.

You can check any assumptions about the code. But it's not exactly like using browser's dev tools console. First — you don't have to type things "somewhere else" — you're doing it right where you're writing code. And it can be a file or a scratch buffer — you don't even have to save those experimental bits. Second — because you have things neatly wrapped into symbolic expressions (those pesky parens that non-lispers find so confusing), you don't need any ceremony for setting up the stage.

take this Javascript example:

    function addFive(x) { return x + 5; }
    
or

    const addFive = (x) => x + 5;
And its counterpart in Clojurescript:

    (defn add-five [x] (+ x 5))
In javascript REPL you can eval the entire thing, but try doing it piecemeal - it makes little sense, i.e., what is (x) or => from js perspective, semantically? While Clojure variant already is a list - a native data-structure, the argument is just a vector - another native thing, etc.

So that infamous code-is-data & data-is-code mantra may not seem like a big deal in a trivial example like this, in practice, it's very nice, it allows you to do things otherwise difficult to achieve, watch this video https://www.youtube.com/watch?v=nEt06LLQaBY and give it a thought, how does one build something like that and how using a Lispy language helps there, while using more traditional PL would make things much more difficult.

> It sounds like you write code as black box then run it in REPL to see what it does because you don't understand it by yourself.

That doesn't even make any remote sense. "I don't get the fixation with the JVM. It sounds like you write code as a black box, then compile and run it to see what it does because you don't understand it by yourself."

[dead]

My understanding is that Lisp and most functional languages map very well to PL theory and how compilers and interpreters manipulate programming languages (functions as graphs of code, types as contracts etc.), while procedural languages map well to how CPUs execute programs, and the abstractions operating systems provide (functions as mappable pieces of memory, types as memory or register layouts etc. )

Let's be real in most situations it doesn't matter. One "statement" per line is bog standard. Whether that statement is surrounded by parens or ended in a semicolon isn't impactful for reading.

LISP is only better when you add source code transformation (which is way easier with its source code looking like the transformed code). But then you introduce "everyone can write their own syntax" which is good and bad given the history of DSLs...

> One "statement" per line is bog standard

This isn't really true. Most non-Lisp languages I work in, like JS or Ruby or Python, have things like long_expression =\n long_other_expression, or long_expression\n.another_long_expression\n.another_long_expression.

And if most of your code looks like that you are making a mistake.

"Sometimes I need multiple lines" is fine, exceptions happen.

But again I ask, visually are those lines super different?

Ditto for things like for loops which have multiple statements in a line.

When writing code you are transforming it all the time. Having only expressions (mostly) comes in very handily. It is called structured editing of code.

<3

Are n4ture and torginus the same person?

Why the exact repeat of the earlier post under a different name or some bots at play here?

It's not an exact repeat.

Stop karma whoring!!

If it is not suspicious then why has the comment been deleted, causing this comment to rise to the top level?