Hacker News new | ask | show | jobs
by wwosik 2060 days ago
I don't think I like it. I find it hard to quickly skim and find out what each of the elements is, since it can be anything.

The example amounts to:

  function drawTriangle(left, top, right, color) {
    drawLine(left, top, color);
    drawLine(left, right, color);
    drawLine(top, right, color);  
  }

  drawTriangle({ x: 0, y: 0 }, { x: 3, y: 3 }, { x: 6, y: 0 }, "blue" );
  drawTriangle({ x: 6, y: 6 }, { x: 10, y: 10 }, { x: 6, y: 16 }, "purple");
Maybe it's a case of getting used to it, but with my version I can very quickly ignore parts of code, which are not relevant to the thing I'm looking for.
3 comments

Indeed, I think this post ends up being a good argument against Lisp. The supposed negative for JS, as opposed to Lisp, is that "We’d need something like Babel to parse our file, and work on top of the AST to make sure we rewrite our code safely." And? Computers are good at parsing, and adding syntax to a language should be comparatively rare, so why would I choose a language that optimizes for this case, rather than one which optimizes for human readability?

I think some people will argue that macros shouldn't be rare, that you should define a custom DSL for each application so you can work at a higher level of abstraction. However, macros themselves operate at a fairly low level of abstraction (operating on the AST, rather than closer to the problem domain). I would argue that if you find yourself using macros frequently, that's a sign your language is lacking in higher-level abstraction capabilities.

> Computers are good at parsing,

And humans are even better at it, and actually seem to cope with typographically diverse syntax better than the uniform ones. So it absolutely makes sense to have a nice, heterogeneous, human-friendly syntax.

As for writing custom DSLs... I always feel vaguely uneasy when I find myself writing, essentially, an interpreter/VM for a simplistic programming language in a form of a set of library routines/components that I then process to use to build my application logic out of. After all, I am already writing code in a rich programming language, why don't I just use it for my application logic in the first place?

> After all, I am already writing code in a rich programming language, why don't I just use it for my application logic in the first place?

I'd assume it's because that rich language isn't as well-suited to the problem domain as the DSL. I think one solution might be to come up with a more principled way of writing DSLs, that don't require you to revert to writing an interpreter or compiler "from scratch".

> Computers are good at parsing, and adding syntax to a language should be comparatively rare, so why would I choose a language that optimizes for this case, rather than one which optimizes for human readability?

Having everything be uniform has other advantages, but I think they end up being more subjective. Some people like the regularity, because they don't have to remember so many different kinds of syntax. Other people prefer different kinds of syntax, because they find it easier to read. I don't think there's an object measure here, because it all depends on your past experience and your preferences.

Going with the example in the article and the nominal purpose of it... how would you take what you’ve written above and parse/execute it without using eval.

I’m with you, generally. I have used CL off and on for the last 20 years, and when I come back to it it takes a solid week before I start “reading in Lisp”. It definitely doesn’t come naturally when you spend most of your time reading “C-type” syntax all day. But for some tasks it is an absolutely fantastic tool and doesn’t take that long to get back into.

Genuine question since I might be missing something: how would you take the lisp version and parse/execute it without using something like eval?
I'm not sure if you mean in JS or in CL, but it works basically the same way: deserialize it (not eval) and walk through the array, doing the exact same kind of steps they're doing in the article for the JS version. Build up a symbol table (or two, if your function names and variable names are in different namespaces). The evaluation rules are so simple and consistent that the logic required while walking the array is pretty tiny.

To do the same thing with Javascript code involves parsing into an AST and walking the that tree; the hard part is that the rules for walking that tree are dramatically more complicated. In the Lisp case, the AST and the original code look very similar; in the JS case, they diverge quite a bit (there's a ton of crazy things in the JS spec if you dig through it)

I think this actually gives a better intuition for Lisp syntax: https://www.defmacro.org/ramblings/lisp.html