12 ms·
An Intuition for Lisp Syntax
- martyalain 5y agoHi Stepan Parunashvili, I enjoyed your post "An intuition for Lisp syntax" - https://stopa.io/post/265?repost=true and I wonder what you could think of this another one: - http://lambdaway.free.fr/lambdawalks/?view=coding - http://lambdaway.free.fr/lambdawalks/?view=fromroots2canopy Best regards Alain Marty
- wearywanderer 5y agoI know different pedagogical approaches work for different people, but in my experience the fastest and easiest way to learn Lisp is to bite the bullet and jump right into it. I think when it comes to the parentheses of Lisp, the premise is straightforward; there just isn't a whole lot to actually learn. I believe most of the difficulty comes from people psyching themselves out before they even try. That describes my personal experience with the matter anyway. Also with regards to prefix notation being unintuitive: We already teach something very similar to schoolchildren learning arithmetic: 1 + 2 --- Here, as with (+ 1 2), the operator is on the left most side. The operands are arranged horizontally in lisp instead of vertically, but the supposed weirdness of the operator being on the left doesn't seem to bother people when it comes to arithmetic.
- cuddlybacon 5y agoI always read that as (1 + 2). I read it left to right, then top to bottom, so it would read as [null, "1", "+", "2"] and not as [null, "+", "1", "2"].
- HDMI_Cable 5y agoI've always read 1 + 2 --- as [1 2 +]. I guess it's a difference in perception.
- wearywanderer 5y agoTbh I generally vocalize (+ 1 2) as "one plus two". Casual English usually uses infix notation, but I think "add one and two" is valid and generally understood.
- wk_end 5y agoI almost wonder if Lisp pedagogy would be improved if the ‘+’, ‘-‘, etc. operators weren’t introduced for some time, and maybe instead ‘add’ or ‘subtract’ were taught instead. There’d be less knee-jerk opposition to the lack of infix notation.
- e3bc54b2 5y agoThen it would become complaint against verbosity by those who only saw first lesson of a lisp book. For someone who started learning Lisp way way late in my programming journey, I would not have appreciated it had I not went through half dozen other languages before. The sheer simplicity of the foundational concept is liberating. That simplicity means Lisp actively encojrages exploration (which is why you see so many Lisp dialects). Unfortunately, most people don't really learn anything new unless they were forced into it. Most people, aren't into exploration. They treat language as a short-term tool to get paycheck, and anything making them use more braincells, even to their own long-term benefit, is an annoyance. To each their own, its just that as good as Lisp is, its MO don't map well with that of most populace.
- moonchild 5y ago> complaint against verbosity Not an unjustified one, in fairness. Lisp tends to prefer long, descriptive names.
- e3bc54b2 5y agoAgreed. Even more of a reason to not make + into add and - into subtr. I've thought about how the verbosity can be avoided, but at certain level of complexity, it is better to have long descriptive names, but I'm not experienced enough with big projects to propose a solution.
- deleted 5y ago[deleted]
- pxc 5y agoInvoking something at the command line is also prefix notation, and it's something programmers do all the time.
- musicale 5y agoI seem to recall mixed columnar addition and subtraction: 3 + 4 - 5 --- 2 which was read as "3 + 4 - 5 = 2"
- Zababa 5y ago> The operands are arranged horizontally in lisp instead of vertically, but the supposed weirdness of the operator being on the left doesn't seem to bother people when it comes to arithmetic. I'm not sure I agree. I would argue that people read your example left to right, top to bottom, which would be "1 + 2". At least for people that read their native language this way. Maybe people who read from right to left would read "1 2 +" and be predisposed to Forth?
- lallysingh 5y agoThe list syntax isn't really a grammar but a data structure spec given to the compiler. The only power here is in using the same data structure. It's very powerful, but that's the basis of it.
- Koshkin 5y agoTo those who find "that all those brackets in Lisp were off-putting and weird", look no further than C++: [](){} is valid syntax for a lambda. (I think in C++20 you can also stick in < > somewhere in between.) Lisp's S-expressions are just acquired taste (like coffee of a particular blend).
- kccqzy 5y agoThe following are all valid too: []{} []{}() [](){}()
- opportune 5y agoDoesn’t look weird to me, that’s just an empty lambda. Pretty recognizable for anybody who works with lambdas, IMO - it’s just an empty capture with no parameters and no body. Not something you would ever see in real code unless doing something very weird.
- owl57 5y agoStrange in fact that we don't recall seeing this in real code. An empty callback smells a bit sloppy but not really weird.
- owl57 5y agoSee? Lispers sneaked in, distracted everyone with all these lambdas and closures and put their brackets all over the place.
- fishmaster 5y agoOpen and shut case, Johnson!
- abrolhos 5y agoAnother perspective is this one: https://www.defmacro.org/ramblings/lisp.html https://www.defmacro.org/ramblings/lisp.html
- stopachka 5y agoLoved that essay!
- kazinator 5y ago> Every lisp hacker I ever met, myself included, thought that all those brackets in Lisp were off-putting and weird. Not me. I used C before Lisp, and Pascal before that. C replaced syntax like BEGIN and END and "END <procedure name>" with just { }. I thought this was a most excellent thing. I was still not using Lisp when HTML and then XML came along. My reaction to XML was this: since most of the content of XML is payload data, why don't we just fscking use parentheses or braces to structure it? Some {foo bar {baz}} or whatever instead of this moronic, bandwidth-wasting, unreadable nonsense <foo>...</foo>. I could understand it when the markup is just a few raisins in the pudding like: > Lorem ipsum dolor sit amet, <i>consectetur</i> adipiscing elit, sed do eiusmod but this XML thing made no sense as a data notation in which every little leaf element is wrapped in verbiage. So then when I got into Lisp, it basically had the syntax I already wanted; it was "pre-approved". I already liked parentheses because they occur in English prose (like this), in mathematics, and in almost every programming language I had ever used. The Unix shell and other command languages eliminate the commas: we don't write tar, czvf, foo.tar.gz, foo Moreover, command arguments are not restricted to narrow lexical categories like "must begin with letter or underscore ..."; they are just clumps of non-whitespace characters. If you know any command languages, what Lisp is doing in that regard is obvious; you're not confused by a+b just being an argument, different from a + b. Commands with the main function on the left followed by space-separated arguments occur in parentheses in POSIX command substitution syntax: printf "[%s]\n" "$(cat file1 file2)" > file3 dironly=$(basename $(dirname a/b/c)) In general, by the time I got into Lisp I had written so many scanners and parsers, solved so many shift-reduce and reduce-reduce conflicts and whatnot, I knew a good thing when I saw it.
- threatofrain 5y agoYAML sort of addresses this, but I really wish companies would just go with Lisp when they want to do weird DSL's, such as, ahem, Ansible with their weird YAML. As weird as Lisp is, it can never be as weird as learning idiosyncratic languages for different products. It is the most minimalist machine-human compromise for lists of lists.
- smw 5y ago
- fungiblecog 5y agoI maintain that the problem with Lisp for most programmers coming from C-like languages is not the parentheses. It's the fact that lisp style is heavily oriented around expressions (since almost everything is an expression) which leads to a lot of nesting and a functional style, rather than a block-oriented imperative style.
- shrimpx 5y agoBut even a block is syntactically just a list of statements.
- Blikkentrekker 5y agoThe same applies to Rust, or Haskell, but I see no such common criticisms leveled against it.
- lgas 5y agoI can't speak to Rust, but I suspect in the case of Haskell the criticism doesn't arise because the whole language is so foreign to people coming from C-like languages that everything being an expression is just one of many hurdles. So it doesn't stand out as much on its own, and either you give up or by the time you make it through enough of the other hurdles you probably appreciate the expression-orientedness. I say this as a Haskell enthusiast. Do-notation probably also masks the fact that everything is an expression from newcomers a bit in the beginning.
- scotty79 5y agoI think it's lack of infix operators. People tend to love those.
- waynecochran 5y agoLisp doesn't really have (much) syntax. The programmer is directly creating a collection of syntax trees (more or less) -- i.e., what most compilers generate after their syntax analysis pass. In fact, you can use Lisp syntax for abstract syntax trees (AST's) as the the output of a parser. Of course it is this very fact that makes code and data interchangeable in Lisp and allows for constructs that other programming languages with syntax can't mimic (e.g., powerful macro features).
- vincent-toups 5y agoNever bothered me. Move the function name into the parens, delete the commas. Nothing to it.
- smabie 5y agoWell, also give up infix functions/operators, operator precedence, readable equations, etc. Most Lisps have syntax anyways, in order to make the language less verbose. There's a reason people like syntax, because it is expressive.
- filoeleven 5y agoYou don’t give up operator precedence, you just write it explicitly. Operator precedence is a consequence of implicit infix operator behavior. What is the value of this statement? 3 + 100 % 2 / 5 I’d like to have added a power calculation somewhere in there for illustration, but most general-purpose languages make that a function. It’s worth asking whether they ran out of infix symbols/syntax or chose a function for some other reason.
- owl57 5y agoProbably the former. Python seems fine with infix **. But Python doesn't have pointers: C++ designers would have to invent something less conventional (not that they aren't famous for unconventional horrors, though).
- cellularmitosis 5y agoIt seems like the infix issue would be a pretty simple modification to eval: if the first thing isn’t callable, try the second thing. But I’ve never seen this done, so it must be more complicated than I realize.
- GavinMcG 5y agoThe problem is that the first thing might be callable, and it might expect one or more arguments that could include functions. If your intention was to add something to the result of a function, but + was passed as input to that function, you wouldn't get what you expected.
- smabie 5y agoI used to really like Lisp and did some professional programming using both Racket and CL. But now I don't really like it anymore and parenthesis do put me off. The benefit of easy AST manipulation just doesn't seem worth it when the cost is a very heavy and verbose syntax. Everything just takes a little longer to write in Lisp, and the syntax is far too noisy. Moreover, languages with powerful and easy to use macros (like Julia) don't have a paren heavy syntax, so what value does Lisp syntax really even provide anymore? New languages have demonstrated you don't have to sacrifice a lightweight syntax and expressive macros. It also makes writing any sort of code that uses equations incredibly burdensome to write. In short, while Lisp syntax used to serve a purpose (facilitation of macros/modification of AST), I feel like it no longer really does. For comparison, I think OCaml syntax is really nice: light and readable.
- jimmyvalmer 5y ago> Everything just takes a little longer to write in Lisp Missing obligatory preface of "unpopular opinion".
- maydup-nem 5y ago> The benefit of easy AST manipulation just doesn't seem worth it when the cost is a very heavy and verbose syntax. Wat. "Very heavy and verbose syntax"? Are you even sure you are talking about lisp?
- smabie 5y agoI mean, even lispers acknowledge that, that's why things like CL loop macro exist. That's why reader macros exist.
- nicolodavis 5y agoWanted to add that Lisp maps quite well to visual programming languages: https://boardgamelab.app/blog/visual-scripting/ https://boardgamelab.app/blog/visual-scripting/ You get the benefits of writing code composed of neat delineated expressions that nest arbitrarily but without the verbosity that parentheses add to the source file.
- moonchild 5y agoBetter example: https://github.com/disconcision/fructure https://github.com/disconcision/fructure
- jampekka 5y agoIs this really about syntax? I think this is about homoiconicity. But homoiconicity is NOT the same thing as parenthesis, (or brackets as here)! Homoiconicity is not a (concrete) syntax issue, it's an AST and semantics issue in my view. Why are we so hung up on the superficial details of the syntax. Can't we just have an AST spec with bijective mappings between different human presentations? Editors already do color coding for us and people use different fonts for their code, but flamewars about what colors and fonts are quite rare. I don't see this as anything fundamentally different. Is it somehow difficult to accept that different syntax may map to identical AST? Lisp is intentionally syntactically very close to its AST and I find this elegant. But why are we so hung up that the human interface for this has to be parens? Are people confused somehow that wanting to use different syntax means they want to change the language? Even if it no way forces people not to use parens if they want. Can't "the language" just be the AST? Am I overlooking something? I find this to be an almost trivial solution to many many neverending flamewars. I personally don't like parens because I want computer to do what it does best, which is doing routine churn like matching up parens. I don't mind if somebody else wants to see the parens. Why should I mind? The computer doesn't care at all. Multiple people could edit the very same code, one with parens, one with brackets and one without either (e.g. significant indentation). The EMACS solution is paredit or something where the editor tracks the parens. But why do these have to be there at all if the computer already knows how to track them? For me this is almost identical issue to C-family semicolons, tabs-vs-spaces indentation, formatting guidelines, the Guido colon, significant whitespace etc. Is this some authority or status or tribal thing or something? Or cultural lag from moveable type era? I don't get it. Why people find it so important how other people use want to see the superficial syntax? It's like having strong opinions how other people should paint the interiors of their house to me. Or is there some mix-up between form and function and we have different understandings where the separation goes? BTW, I recall seeing this post before, but it's not dated. As per wayback machine this has been published in 2020, and seemingly just has "repost=true" GET-variable for "dupe-busting(?)". Shouldn't this be marked as (2020) in the title?
- klyrs 5y agoI do metaprogramming in quite a few languages -- Python is the worst, and lisp is the best (and I've got literally thousands of times more experience with python). To me, homoiconicity is huge -- especially the comma and backtick operators make it a breeze. If you don't metaprogram, maybe you don't care -- but if you care at all about performance, a tiny collection of features it enables a whole new programming paradigm. Contrast this to Python. The best feature is f-strings, which approaches the ease of backtick/comma. But the lack of homoiconicity means you can't just jam a bunch of statements in a list -- for crap's sake, indentation makes everything a pain.
- huachimingo 5y agoLisp is Polish Notation but Forth is Reverse PN. I wonder if the same constructs can be made in terms of the other language.
- js8 5y agoNo. There are three fundamental ways to encode a syntax tree - prefix, infix, and postfix. Haskell (ML) is prefix, Lisp is infix, and Forth is postfix. (I.e. Forth-like is the opposite of ML-like, not Lisp-like.) The advantage of infix is that you don't need to know the argument counts for functions/macros to reconstruct the tree, but the disadvantage is extra parens. I am slowly coming to (subjective) conclusion that postfix is the most natural, because it's the same as the (typical) evaluation order.
- moonchild 5y agoWhy should I concern myself with the order of evaluation? I want to think about my programs from the top down, not the bottom up. What about laziness, which disrupts this apparent order and in fact evaluates from the outside in?
- js8 5y agoYou don't have to anything, I said it's subjective. I prefer ML-like to Lisp-like, because I want typechecking anyway (which involves counting arguments) and this means most Lisp parens we can dispose of. And lately, I noticed I use a lot of "$" (apply) in my code, and while it reads left-to-right, it mostly evaluates right-to-left. So why not switch to Forth-like, which reads and (mostly) evaluates left-to-right?
- dreamcompiler 5y ago> Haskell (ML) is prefix, Lisp is infix, and Forth is postfix. With respect, no. Lisp is by default prefix (Polish notation) but with some work you can make it behave as infix or postfix. Haskell is naturally either prefix or infix depending on how you define and call your functions (the use of backticks or parens around the function name in a call changes it from prefix to infix and vice-versa. It's a rather elegant solution to the problem.) As you stated Forth is postfix (Reverse Polish notation).
- jangid 5y agoWhat I like about Lisp's syntax is that the cursor (point) is always in a complete Lisp program. You move up one set of parenthesis, again a complete program. Move up further .... till you reach the top (file-level). So this gives good opportunity to Editor makers. Compile "this" level, 1-level-up, 2-level-up and so on. In an editor you can always check your program while coding. Example is Cider package for Emacs for Clojure programming language.
- deleted 5y ago[deleted]
- Blikkentrekker 5y agoThis isn't necessarily true, as various special forms have keywords with special meaning themselves that are enclosed in parentheses. This is a complete Scheme program: (cond [(= 1 0) (error "should be unreachabe")] (else "should always be reached")) However this: (else "should always be reached") Is not a Scheme program, unless the binding `else` be defined in the current scope..
- owl57 5y agoIs the second one less of a program than (frobnicate "foo")? Looks about the same to me: a program that crashes unless we (define frobnicate …) first.
- Blikkentrekker 5y agoCrashes? in most cases simply does not compile because Scheme has static scope; it is thus not a program. But, we can of course go even further than that: (library (main constants (0 0 1)) (export pi) (define pi 3.1415926535) ) `(0 0 1)` is not a valid Scheme program, no matter what one define at any point; an integer can never be the operand of an expression.
- dTal 5y agoIt is for this reason that it is misleading to say that lisp languages "have no syntax" - they do have considerable constraints on their structure. It's almost as if there's a third layer between "syntax" and "semantics" - or perhaps the word "syntax" conceals two distinct types of structure.
- wydfre 5y agoI love Lisp syntax because I am stupid. It is actually easier to remember. Remembering the function names and library calls is difficult for me because of my disability. But because there is no syntax it is so easy to parse in your head.
- raspasov 5y agoThis. After you understand how Lisp works, syntax and "features" in other languages feel pretty awkward, to put it mildly.
- scotty79 5y agoWouldn't lisp done with indents and newlines instead of brackets and whitespace be fun? Edit: Apparently there's alternative syntax for Scheme called wisp.
- e3bc54b2 5y agoAs someone who hated the whitespace in python and hates it even more in yaml, please don't. The only significance whitespace should have is its presence or absence, beyong that, its a pain for human readability.
- scotty79 5y agoAs someone who loves whitespace in python and for whom coffeescript is as close to perfection as as typeless JS can be, I can't oblige. For me brackets should mostly serve a decorative function and rarely ever be nested or span multiple lines or screens. In the spirit of compromise I'd like to see text ediors where bracekts or no brackets is just a visual toggle you can switch back and forth on a whim.
- jampekka 5y agoWhy do you hate it? General claims about "human readability" is quite suspect, or then it implies I'm not a human?
- e3bc54b2 5y agoFair enough, I should explain. When I'm reading or writing code for Java,or C I am reading or writing code. My brain parses all the visible characters and safely ignores the invisible whitespace. Indentation is just better readability. When I'm reading or writing Python/Yaml, suddenly I'm having to pay attention to what is not visible to my eye as well. Its extra cognitive load and that reduces readability.
- jampekka 5y agoSorry for the late response, but I find this interesting. I've encountered similar reports earlier regarding this question. There may be quite fundamental differences in how people "see" code. I don't pay any attention to the block delimiters, and am easily fooled if the indentation doesn't match the block structure. Do you ever make the infamous semicolon-after-if-clause bug in C? I do sometimes and it can take ages just to see that semicolon.
- Rerarom 5y agoMy initial problem with parentheses wasn't the stacking of them -- that's inevitable even in elementary arithmetic -- but with the fact that x is not the same as (x), which doesn't happen in math and doesn't get emphasised enough in Lisp intros. Once I got that, everything was easy. Edit: To answer to the responses to this comment, it's not that it's conceptually hard, it's just that the parenthesis symbol in its usual incarnation does not work that way, which leads to confusion.
- lisper 5y agoIt's no different than x being different from x() in C-like languages.
- dhanvanthri 5y agoI mean it's literally the same idea as in set theory. phi is an empty set, (phi) is a set containing an empty set ((phi)) is a set containing a set containing an empty set Furthermore, it's one of the only syntax rules; if it's not a list, then the first element is an operator/function.
- Rerarom 5y agoI agree with that, but in set theory the symbol {} is used. I have nothing against it, I just think it should be emphasized more.
- Koshkin 5y agoHmm, never thought of ∅ as a φ. (According to Wikipedia, the symbol was introduced in the 1930s by Weil, inspired by the letter Ø in the Danish and Norwegian alphabets.)
- musicale 5y agoThere is the old joke about any significantly advanced program in (C/C++/Java/whatever) evolving into a crappy lisp implementation. Of course some (emacs) omit the initial steps and jump right to the steady state.
- hello_goodbye 5y agoAnd emacs certainly is just a rubbish lisp implimentation. (joking)
- emmelaich 5y agohttps://en.wikipedia.org/wiki/Greenspun%27s_tenth_rule https://en.wikipedia.org/wiki/Greenspun%27s_tenth_rule
- ngcc_hk 5y agoShould have a lisp example ...
- thatspartan 5y agoAs I read this, Greenspun's tenth rule of programming humorously came to mind: "Any sufficiently complicated C or Fortran program contains an ad hoc, informally-specified, bug-ridden, slow implementation of half of Common Lisp." Generalized by replacing "C or Fortran" with a language where the user wants more power over it's syntax and semantics, to witness the author pull it off in just 44 lines of JavaScript was a joy.
- abrax3141 5y agoThis is honestly not worth debate. It's like arguing about having kids (whether pro or con) with people who don't have kids. There is no way to have the experience of lisp without being an experienced lisp hacker.