5 ms·
This is really cool, I like it a lot! I don't think the parens in lisp are actually the problem, I think it's the embedding. I.e. List programps naturally tend
by benrutter 2y ago
This is really cool, I like it a lot! I don't think the parens in lisp are actually the problem, I think it's the embedding. I.e. List programps naturally tend to get very nested very fast, kinda like this:
(-
(+ (* 3 4)
(- 3 1))
3)
It's just a simple sum, but reading it involves a lot of remembering contexts and how things should work in lisp. The CWP examples uses arrow/pipeline style macros a bunch, which are awesome! I kinda feel like they already solve the issues that a lot of people have with parens:
(->> 3
(* 4)
(+ (- 3 1)
(- 3))
There's still a tonne of parens there, but the flow is a lot more readable for me.
Edit: sorry for the very difficult to read code formatting - couldn't figure out how to monospace things in hackernews.
- genezeta 2y ago> Text after a blank line that is indented by two or more spaces is reproduced verbatim. (This is intended for code.) [0] So... (- (+ (* 3 4) (- 3 1)) 3) And... (->> 3 (* 4) (+ (- 3 1) (- 3)) [0] https://news.ycombinator.com/formatdoc https://news.ycombinator.com/formatdoc
- benrutter 2y agoAh nice, thank you!
- geokon 2y agoI often write threaded math but it unfortunately it doesn't compose cleanly with division :) (subtraction can be transformed into an addition without too much extra) If you do thread-last and then need to divide by some value, you will need to write something like (* (/ 1 37)) which is ugly I think you could actually write a fraction here, but if instead of 37 you have a binding then that doesn't work
- Someone 2y agoForth does that without parentheses: 3 4 * 3 1 - + 3 - That’s the ultimate “object verb” way to do it and IMO at least equally readable (ignoring familiarity, of course)
- xigoi 2y agoThe problem with this is that the parsing depends on the arity of the functions.
- tmtvl 2y agoWouldn't that be true of infix syntax as well? For example, if I define an operator, %, which divides one number by a second number and then multiplies it by a third, you have to know its arity to parse: 70 % 90 100 * 10 Even worse, in this case you're also dealing with operator precedence, which in (Reverse) Polish Notation isn't an issue.
- xigoi 2y agoYes, but infix syntax is usually used only for a few select functions, whereas Forth uses postfix syntax for all functions.
- tmtvl 2y agoIn Forth parsing doesn't even come into play, because an operator just tries to pop as many arguments off the stack as it needs. Annoyingly, that does mean there's no way to tell what the following: a b + Means, as it can be any of these, for example: add(b, a) add(b(a)) add(b(a())) add(b(), a()) add(b, a()) add(b(), a) In a language where you don't need brackets for function calls it can be reduced to: add b, a add b a And even if the add function takes two arguments the second option would be fine because the call: b a May put two arguments on the stack. add(b(), a())
- ledgerdev 2y agoAn excellent point about lisps. I've long thought that one of the core issues with lisps is that logic is tree based, where a large majority human brains are far more amenable to linear process. I suspect there's un-recognized cognitive overhead in the branching of trees versus linear with early return.
- lispm 2y agoThe problem is that the Lisp code structure is hierarchical. Transforming it for input/output into a sequential code structure can help, but hinders the learning of the hierarchical mode of working with trees and nested lists. In the long run the mental model of trees or nested lists is more important than the "improvements" of the sequential visible structure. Typically the sequential model is preferred by those who have learned other languages with imperative code structures (in the history that was FORTRAN, but nowadays it's often languages like Python and Java). Not unlearning and then learning a different model, limits the understanding of the underlying language and its evaluation model.
- benrutter 2y agoThat's really interesting! I definitely could be sticking to a mental picture without realising. Curious if you're a lisper and have got used to reading that kind of heavily intended code? Or if you have other strategies for minimizing the complexity?
- lispm 2y agoFor me containment is important. (a (b)) -> (b) is inside a. Also that the whole form is enclosed in parentheses. If I move the mouse over a form, the whole form can be selected. (pipe (a 1 2 3) (b 4 5 6 7)) If I move over the second form, there is an argument, which is above it. My mental model is more based on tree evaluation, not so much on sequential evaluation. (b (a 1 2 3) 4 5 6 7) For me it's more important to see that all arguments to b are enclosed in a single form. If I want to move it around, I can easily select the whole form (with the mouse typically by a double click on the parentheses or a middle click). The list becomes a physical thing (-> manipulating lists), not so much a syntactical thing (dealing with the syntax of a pipe operator). But then I'm used to Lisp environments with a higher code complexity (longer code with deeper nesting, lots of macros) and support for that.
- tmtvl 2y agoMathematical notation often gets brought up as an example of there being problems with Lisp syntax. I have problems with that. For one, how often do you actually write... foo := 7 * 3 + 4 - 5; Instead of: foo := 20; Which, in Lisp syntax could be as simple as: (set! foo 20) I could see an exception being made for something like: constant MEMORY := 640 * 1024; But the Lisp equivalent: (defconstant! MEMORY (* 640 1024)) Isn't _THAT_ much worse. With more complex examples we still see that the difference isn't too terrible, especially as we try to make code more readable. An example of code whose readability is questionable could be: r := (t - l) / (n - 1) * n; Which, when we choose names with a little more meaning could become: readjusted_score := (total_score - lowest_score) / (number_of_students - 1) * number_of_students; Of course, that line is a bit long (just a bit, but I'm not interested in actually going and typing out a very long line), so it could be reformatted to something like: readjusted_score := (total_score - lowest_score) / (number_of_students - 1) * number_of_students; Which isn't _TOO_ much different from: (set! readjusted-score (* (/ (- total-score lowest-score) (- number-of-students 1)) number-of-students)) And in fact, the Lisp syntax could make certain errors more visible, such as when we compare the following two snippets: readjusted_score := (total_score - lowest_score) / (number_of_students + 1) * number_of_students; (set! readjusted-score (* (/ (- total-score lowest-score) (+ number-of-students 1)) number-of-students)) And yes, indeed, when we start looking outside of mathematics, sometimes a little bit of sugar can even reduce the amount of brackets needed in Lisp syntax beyond the brackets needed in non-Lisp syntax: abstractFactoryInstanceBean := AbstractFactory.getInstance().getBean().initialize(); (set! abstract-factory-instance-bean (-> Abstract-Factory get-instance get-bean initialize)) Speaking purely of mathematics, writing a function which turns infix syntax into Lisp syntax isn't too daunting anyway, it's even an exercise in good old SICP, so with very little effort we could write a macro to let us do the following: (set! foo (infix bar + baz * (quux - zot))) Or, for the RPN aficionados: (set! foo (rpn bar baz quux zot - * +)) Of course this is very much personal opinion, but I would even go as far to say that infix notation isn't even that popular, as we can see with the following examples: new_student := new Student("Name", points); new_student := Student new ("Name", points); if (length(students) > 30) { error("Too many students in class!", length(students)); } else { addStudent(new_student, class); } (length(students) > 30) if { "Too many students in class!" error length(students); } else { new_student addStudent class; } All of that being said and done, I doubt I will change anyone's mind, but I personally really like Lisp syntax (as in good old, double open brackets on the let, Lisp syntax), and I just hope to see arguments which are a little stronger that the old classic 'we learn 1 + 2 in school, not (+ 1 2)'.
- makizar 2y agoThe best effort I’ve seen at working around lisp’s parens notation and make its syntax more declarative-looking is Rhombus, which is based on Racket, and actually on track to replace it. what it looks like: https://github.com/racket/rhombus/blob/master/demo.rhm https://github.com/racket/rhombus/blob/master/demo.rhm more info: https://doi.org/10.1145/3622818 https://doi.org/10.1145/3622818 https://github.com/racket/rhombus https://github.com/racket/rhombus