10 ms·
An Intuition for Lisp Syntax (2020)
- 100001_100011 4y ago"There lies our problem: we can’t use eval" And there lies the solution: fix eval.
- qsort 4y agoYeah, just casually solve the halting problem while you're at it, why not.
- bdowling 4y agoIf the language subset can't loop, can't recurse, can only call functions that are guaranteed to finish in finite time, and only allows finite-length programs, then its programs will always halt in finite time.
- topaz0 4y agoFixing eval is almost exactly what the OP does. It's not that hard. Everyone who has written a toy lisp can do it.
- Banana699 4y agoThe key to solving the halting problem is realizing that you don't need to solve the halting problem. Problem : Code C has to run in finite time T, Solution : put a call to a watch dog routine at every loop start, at every subroutine start, and every n linear instructions in C. If the watch dog decides T has passed, it never returns control to the program (calls exit(-1), throws a special uncatchable exception,...). This can be automated by the compiler. This is why AWS can give you a limited time for a Lambda or why every single multi-tasking OS can terminate an unresponsive process. They are not solving the halting problem. If the language C is written in is bytecode-interpreted, you don't need to modify the guest program itself to achieve the described effect, you can make the interpreter itself keep track of T and refuse to evaluate further when it runs out. If the execution environment is preemptively concurrent, you don't need to modify the host program as well, simply make the watch dog preempts the guest at T.
- praptak 4y agoMy intuition for Lisp syntax is "The opening parenthesis moves one position to the left. Drop commas, keep whitespace.". So: f (x, y, z) becomes (f x y z)
- bkirkbri 4y agoSame here. I never understood why a paren on the left of a function name “looks like fingernail clippings” but to the right it’s “just how code works.”
- taeric 4y agoAnother plus one here. The commas baffle me, as more languages decided to add optional trailing ones...
- qsort 4y agoLarry Wall's remark was less about prefix notation and more about how there's very little visual difference. I don't necessarily agree with the criticism because that's the price you pay for homoiconicity, and it's a price well worth paying; but it was a more serious complaint than "lmao parentheses". See e.g. Clojure, that introduced #{} for sets, [] for vectors etc.
- Banana699 4y ago>that's the price you pay for homoiconicity Well no but actually no. Mathematica is homoiconic, and it has tons of special syntax and sugar that all boils down to lists when you quote. Elixir also does this with a ruby-like syntax on top. Those are just the 2 I know of. Making the compiler available through a programmer-accessible API from within the program itself is the big idea, it has nothing to do with what the text grammar happens to be.
- agumonkey 4y agoIt's funny cause to me visual differences in syntax are just useless information overload. And another dimension of constraints to deal with. That's why I clinged to low syntax languages.. you write in semantics almost. The rest is problem solving (or even extending metadomain with macros or else to help yourself)
- behnamoh 4y agoI was personally blown away when I read PG's summary of McCarthy's paper where he came up with a few primitives and built literally any function based on them, including the `eval' function itself. All of this based on some really basic primitives like `atom' and `lambda'. If writing `eval' is possible in the same language you started with, then you must be able to write your own eval, no? Or redefine the primitives? But then what happens if you accidentally set DEFINE to be 5? Restart the buffer? Is there any way to get back to your original definition of DEFINE after corrupting it?
- mtlmtlmtlmtl 4y agoI was gonna respond that you can't redefine the primitives because they're not functions or macros but special forms. And this seems true in Common Lisp. I can't define a function named SETQ(the primitive for assignment in CL, also called set! in other lisps) because it's a reserved name. But then I thought I'd try it in Guile and there I was allowed to (define define 5). Even though define is also a special form in Guile. Which made me unable to define further things, telling me 5 is not a valid argument to APPLY. And no I don't know how to fix it...
- deleted 4y ago[deleted]
- JadeNB 4y agoEvery language has the errors that it thinks you should not be allowed to make, and the errors that it trusts you to make on the assumption that you can determine whether you meant to make them better than the compiler. People complain on both sides of the permissiveness spectrum—they want a language that allows them to make exactly the errors that they want to make, but, of course, that set of errors differs from person to person!
- lispm 4y agoIn Common Lisp you can have namespaces, where you can have your own SETQ: CL-USER 53 > (defpackage mylisp (:use "COMMON-LISP") ; everything from Common Lisp (:shadow CL:SETQ)) ; but not SETQ #<The MYLISP package, 1/16 internal, 0/16 external> CL-USER 54 > (in-package "MYLISP") #<The MYLISP package, 1/16 internal, 0/16 external> MYLISP 55 > (defun setq (a b c) (print (list a b c))) SETQ MYLISP 56 > (setq (+ 1 2) 4 5) (3 4 5) (3 4 5) MYLISP 57 > (cl:setq a 12) 12 Most implementations also have a way to protect core symbols against redefinition and a way to do it anyway (possibly shooting yourself into the foot).
- eatonphil 4y agoSee also, discussion from last year: An Intuition for Lisp Syntax (stopa.io) 130 points by codetrotter on May 27, 2021 | hide | past | favorite | 114 comments https://news.ycombinator.com/item?id=27307388 https://news.ycombinator.com/item?id=27307388
- Jtsummers 4y agoAnd the year before: https://news.ycombinator.com/item?id=24892297 https://news.ycombinator.com/item?id=24892297 - Oct 26, 2020 (198 comments)
- retrac 4y agoMost well-written Lisp code has its structure indicated primarily by the indentation. Some form of offset rule is the most commonly suggested alternative Lisp syntax. It does make the tree structure more obvious: define (define (pos>? p1 p2) pos>? p1 p2 (or (fx> (pos-row p1) (pos-row p2)) or (and (fx= (pos-row p1) (pos-row p2)) fx> (fx> (pos-col p1) (pos-col p2))))) pos-row p1 pos-row p2 and fx= pos-row p1 pos-row p2 fx> pos-col p1 pos-col p2 The left looks a lot like a typical AST for many languages, such as C, shortly after parsing. As the article points out, it's the easy access to this tree-list structure at runtime, that can be easily handled as data by the program itself, that gets Lisp programmers so excited.
- Jensson 4y ago> ))))) You could stack them like this in every language but only in Lisp do people actually do it. Lisps bad habbit of stacking all the parentheses like that is what makes it so hard to read. It is easier to write that way, but it is very hard to understand how many contexts up you just moved.
- lvass 4y agoNot with proper indenting, or rainbow-delimiters/show-paren-mode.
- Jensson 4y agoI don't buy that, when you do the same in other languages you get: for (var i = 1; i < 101; i++) { if (i % 15 == 0) { console.log("FizzBuzz");} else if (i % 3 == 0) { console.log("Fizz");} else if (i % 5 == 0) { console.log("Buzz");} else { console.log(i);}} Why do you think nobody other than lispers writes code like this? Is it really necessary to write code that way? If it is better, why not does nobody else do it? They can also use colored bracers and tooling, while lispers has written code that way forever. I'm sure a big reason people call lisp a "write only language" is because of this strange convention of stacking all parentheses in a big clump instead of formatting like normal.
- reifyx 4y agoHaving played around with Clojure and Scheme for a while (but never got too serious), I always thought homoiconicity and macros were extremely cool concepts, but I never actually ran into a need for them in my everyday work. >Now, if we agree that the ability to manipulate source code is important to us, what kind of languages are most conducive for supporting it? This is useful for compiler programmers, or maybe also those writing source code analyzers/optimizers, but is that it? On occasion I have had to write DSLs for the user input, but in these cases the (non-programmer) users didn't want to write Lisp so I used something like Haskell's parsec to parse the data. The remote code example given in the post is compelling, but again seems a bit niche. I don't doubt that it's sometimes useful but is it reason enough to choose the language? Are there examples of real-life (non-compilers-related) Lisp programs that show the power of homoiconicity? Same goes with the concept of "being a guest" in the programming language. I have never wanted to change "constant" to "c". Probably I'm not imaginative enough, but this has never really been an issue for me. Perhaps it secretly has though, and some of my problems have been "being a guest" in disguise.
- eternityforest 4y agoI actively want people to NOT change constant to c. I want the language to be a predictable shared base, not something I have to relearn and customize for every project. I'm not a language designer. That's hard. That takes time and effort. And I don't do anything that can't be done in Python or Dart or whatever. Customizing the language is time not spent on the project, and batteries included stuff already has everything I need. I think lisp is good for people who "think inside their heads", as in, they think "I want to do this, oh, I could do it this way, then I'd need this resource, let's build it". If you think "Interactively" as in "I want to do this, what does Google tell me others are doing, oh yeah, this was made almost exactly the same use case, I'll start with this resource, now I'll adapt my design to fit it", you might not have any ideas for language tweaks to make in the first place. I basically never code and think "I wish I could do that in this language" aside from minor syntactic sugar and library features. New abstractions and ideas don't just pop up in my mind, what the common mainstream languages have is the entirity of what programs are made of, as far as I'm concerned.
- cjohansson 4y agoLisp is inspiring at first glance, but when you need to solve complex problems like references, pointers, macros, byte-compilation and native compilation it just is not expressive enough like C, C++, or Rust. Neither is Javascript. Lisp could not replace all other languages
- kazinator 4y agoNever mind that Lisp solved references, pointers, macros, byte-compilation and native compilation before the calendar flipped from 1969. Lisp was compiled by around 1960. Peter Landing, in 1964, presented the SECD machine, a kind of bytecode based on Lisp-like lists, directly usable for Lisp implementations, in "The Mechanical Evaluation of Expressions". Numerous Lisps have historically had some kind of "Lisp Assembly Language" (LAP) as an alternative or in addition to native compilation. ZetaLisp, in 1981, the variant of MacLisp running on Lisp machines, featured locatives, which allow the address of a location to be passed around, for simulating reference parameters or members.
- blain_the_train 4y agocorrect. the way i see it, lisp operates at the abstraction level of lists. which most people call "user applications". if you need to build things that build the building blocks of lists it's not a good fit.
- reikonomusha 4y agoThis is just about as accurate as saying "the building blocks of C++ are characters, so if you're not dealing with characters, C++ is not a good fit".
- blain_the_train 4y agoI'm saying that it's hard to build a basic lego block with another lego block. You have to use plastic, heat and a mold. That's why we have a wide range of programming languages at different levels, and why it's common for people to say "high level" or "low level" languages. It's unclear to me what your suggesting, or what question your asking really.
- theowenyoung 4y agoVery great presentation! I made a little toy some time ago [1] with YAML files compiled into Javascript code, in Lisp style, basically along the same lines as the article, and I use this project to manage my dotfiles. The basic syntax probably looks like this: - use: def id: obj args: list: - Hello - true foo: cat: 10 - use: console.log args: - ${obj.list[0]} World - ${obj.foo.cat} - ${JSON.stringify(obj.foo)} [1]: https://github.com/yamlscript/yamlscript https://github.com/yamlscript/yamlscript
- deleted 4y ago[deleted]
- orthoxerox 4y agoThis looks like something IBM would make.