5 ms·
Maybe a more seasoned LISP-`aterian` can answer me ? I'm in the process of learning ClojureScript - real fun so far. I have of course also looked at other LISP
by rawoke083600 5y ago
Maybe a more seasoned LISP-`aterian` can answer me ?
I'm in the process of learning ClojureScript - real fun so far. I have of course also looked at other LISPs and have noticed that in CJS the use of square brackets[] for
vectors, let and `function params`
(defn myfunc []
(let [some-var (:some-key some-state)])
(.log js/console some-var)
)
I almost never see square brackets in other LISPs (yes I'm truly a beginner and haven't looked too hard), but it stiked me as odd ? The square bracket syntax really helps to differentiate and with reading the syntax. (The syntax is not bad it is just different than what most programmers are use to)
Am I wrong or just stupid or is there another reason most other LISP doesn't follow this "convention"?
Again I'm super-newbie, just something that jumped out at me.
- linguae 5y agoRacket also optionally supports a square bracket syntax for cons clauses. For example, in traditional Scheme one would write: ; this is in R5RS Scheme (define (length elems) (cond ((null? elems) 0) (else (+ 1 (length (cdr elems)))))) But in Racket one would write: ; this is in Racket (define (length elems) (cond [(empty? elems) 0] [else (+ 1 (length (rest elems)))])) It is also used in let/let*/letrec bindings in Racket; see https://docs.racket-lang.org/guide/syntax-overview.html#%28part._.Conditionals_with_if__and__or__and_cond%29 https://docs.racket-lang.org/guide/syntax-overview.html#%28p.... I don't know the origins of when brackets started appearing in Lisps. I don't remember seeing brackets in the LISP 1.5 Programmers Manual when using S-expressions (though brackets are a core part of M-expression syntax, which LISP 1.5 still supported), and I haven't encountered brackets in Common Lisp.
- rawoke083600 5y agoInteresting ! Thank you for the examples. Yes Racket is also on my someday-soon-list !
- tralarpa 5y ago> It is also used in let/let*/letrec bindings in Racket I suppose this is just a personal choice of the author of the manual, right? Please correct me if I am wrong but I thought Racket doesn't care whether you use brackets, parentheses, or even curly brackets.
- ltultraweight 5y agoAs someone that was a hardcore Lisper (you could find me arguing that Scheme is not a Lisp, etc.) before adopting Clojure: I thought muddying the language with a new kind of syntax was terrible. I don't suggest that this is what primarily drove the lack of adoption of other kind of braces but I, as a follower of the church of Lisp, had an immense dislike of the lack of purity. In the end vector and map "syntax" is just the reader being more ergonomic in Clojure than in Common Lisp. (See https://clojure.org/reference/reader https://clojure.org/reference/reader for details) After I also got over my aversion of the Java ecosystem and just accepted that the jvm can be great without thinking Java is great, I'm all in on Clojure for the last few years. I think the language is fantastic and due to the huge amount of interop I can use my favorite language in settings that would be difficult otherwise. I've used Clojure on the web as ClojureScript, as backend as Clojure, on a ESP32 and reMarkable as ClojureScript and since relatively recent I can even accomplish scripting tasks with very good start-up times using babashka. I'm a super happy camper and I've found my language for life. A pragmatic Lisp. (duck because stones are incoming.)
- rawoke083600 5y ago>A pragmatic Lisp.. As a newbie(with zero social-capital) I couldn't agree more !
- Guthur 5y agoWell I mean CL is absolutely littered with pragmatism it came out of a standard committee after all. In many ways I'd argue clojure is far more opinionated, it's just an opinion that might more closely align with modern sensibilities.
- patrec 5y agoThe reality is that just about every single lisper will insist how they don't see the parenthesis and they are not a problem, and just about every single lisp has some ugly ad hoc hacks to reduce their clutter. They just differ somewhat between lisps. Scheme (and descendants like racket) went so far as to make [] and () interchangeable. So you will in fact see brackets in some scheme most e.g. (let ([a 1] [b 2]) ...) is a common idiom, although old-school people stick to (). Common lisp has stuff like loop, () aliased to nil (different connotations), and a verbose way to call passed or returned functions; it shares its infix pair syntax (head . tail) with scheme. Scheme, unlike common lisp has a pretty complex (hah) infix-syntax for complex number literals; both write rationals infix. And have a look at the Lisp 1.5 manual some time :) As far as such hacks go, this use of vectors in clojure is actually quite nice. Whereas the fact that clojure, unlike other lisps, uses "invisible" pairing brackets in binding constructs or "visible" whitespace in the form of commas for associative containers is a big pain in the ass for editing and formatting code. [edit: fixed idiomatic let bracket/paren split, as pointed out by version_five]
- bjoli 5y agoOnly R6RS made () and [] interchangeable. That was hugely controversial, with opponents (myself included) thinking it was a waste of 1/3 of the matching pair symbols. And the suggested use was not quite the syntax you showed: http://www.r6rs.org/final/html/r6rs-app/r6rs-app-Z-H-5.html http://www.r6rs.org/final/html/r6rs-app/r6rs-app-Z-H-5.html
- patrec 5y agoI fully agree (and thanks for the idiomatic let bracket ordering correction). But the fact that terribly hacks like this are nonetheless adopted shows how much of a pain the paren clutter is and that claims to the contrary are pure cope.
- mpfundstein 5y agoi maintain two large CL code basis. there is no pain because of parens. really not...
- Munksgaard 5y agoIn Clojure, `[1 2 3]` is a vector, which is a distinct data type from a list, which looks like `(1 2 3)`. A vector in Common Lisp is written using `#(1 2 3)`. Using vectors for function arguments is unique to Clojure, and I'm not entirely sure why they chose to do it that way.
- iLemming 5y ago> Using vectors for function arguments is unique to Clojure, and I'm not entirely sure why they chose to do it that way. Once you understand how destructing works in Clojure, it becomes obvious
- Jach 5y agoUsing [] for syntax like Clojure does is kind of weird and not too consistent IMO. As for data structures, CL has vectors (and more complex arrays), with #() as a literal syntax or my preference just the function (vector ...). But beyond that, CL is just not nearly as opinionated as other languages. You are free to define a function named [] as a wrapper around aref, if you wanted to write things like ([] array index), or you can define a reader macro that uses [ or ] and use them to implement whatever syntactic sugar you desire. That might be as an alternative to #() for vector literals and similar to Clojure, or something that mixes in commas and is more similar to JSON (https://gist.github.com/chaitanyagupta/9324402 https://gist.github.com/chaitanyagupta/9324402), or it could be to use them as syntax where you'd usually use ()s, or as some lambda shorthand e.g. [* _ 10] as shorthand for (lambda (_) (* _ 10)), or as sugar to wrap a special text type (e.g. [hello world] produces an object that wraps the string "hello world"), or to have List Comprehensions e.g. this paper from 1991: https://3e8.org/pub/scheme/doc/lisp-pointers/v4i2/p16-lapalme.pdf https://3e8.org/pub/scheme/doc/lisp-pointers/v4i2/p16-lapalm... whose code (that still works) in figure 2 + the bits right after to the set-macro-character calls lets you write things like [x (x <- xs) (oddp x)] to filter out odds, or [(* x x) (x <- xs)] to get squares, and you can do things with multiple lists. Or something else. Ultimately, it comes back to CL letting you do what you want.
- nlitened 5y ago> Using [] for syntax like Clojure does is kind of weird and not too consistent IMO Actually, it’s very consistent. Round parentheses are used for syntax where the first element is a “command” that will be evaluated, and square brackets are used for list of things where the first element is not “special”. For example, in `(let [x 0 y 1] (conj [2 y] x))` - `let` and `conj` are commands that will be evaluated, and the rest of the syntax list are arguments to that command - `x` and `2` are not commands to be evaluated, they are just members of the syntax list with no special evaluations. The only inconsistency with this rule that comes to my mind is `case` with multiple matches, but outside of that it’s pretty consistent, and I started to like it after it “clicked” in my head.
- Jach 5y ago
- krubar 5y agoIIRC, creator of Clojure, Rich Hickey once said that people in general handle things better where there is some variety in symbols used for different things, when you "scan" the code with your eyes. Too much variety -> you end up with explosion of symbols and operators, not good; too little variety -> hard to distinguish things.
- Kototama 5y agoPrevious lisps had only the list as a datastructure with a special syntax and the program was only represented as lists. There are different "schools" now. Some argue that representing the program only with lists is more uniform and simple. Rich Hickey argues that the different multiple usages of lists in "traditional" lisps, such as in Common Lisp, imposes a cognitive burden so increase the complexity. The Janet language for example follows Clojure whereas as Racket is still a modern language but follows the "tradition".