7 ms·
Out of topic, but as somebody who interested in lisp generally, I have a question, from which dialect would you suggest to start? I am a little bit lost. I am c
by vasergen 6y ago
Out of topic, but as somebody who interested in lisp generally, I have a question, from which dialect would you suggest to start? I am a little bit lost. I am considering clojure, racket and common lisp. I am reading at the moment sicp book and do exercises in `racket sicp package` which is again another dialect. After that want to start with something modern. What was you way to lisp?
- tines 6y agoTo me, the entire point of Lisp, the thing that sets it apart from other languages, is unhygeinic macros. Since that is my view, I can only recommend Common Lisp. CL is the opposite of modern, but just because something is modern doesn't make it good, nor does old make bad.
- bjoli 6y agoAs someone who has written a lot of CL and now deals mostly in scheme, why is an unhygienic macro system important? I don't think it matters much, and frankly I think something like vanilla syntax-case isn't hygienic enough. Either I don't want to care about accidentally capturing identifiers (and be very explicit when I do want it - Day like in srgi-72), or I want to have a system where I deal with explicitly (defmacro) Which I am using matters very little.
- varjag 6y agoIn a lisp-1 like Scheme it's a lot easier to shoot yourself in the foot with unhygienic macros.
- bjoli 6y agoI don't think that matters. Either you write a macro that is correct that won't break because of unwanted intersection with the place of expansion, or your macro is wrong. Edit: barring code-walking macro of course. Once you start using those, the bets are off. Edit2: of course, I don't think overwriting core forms count either. That is poor bedside manners :)
- varjag 6y agoRather than rehash the ancient argument once again, I defer to this post: https://www.xach.com/naggum/articles/3225161536947499@naggum.net.html https://www.xach.com/naggum/articles/3225161536947499@naggum... (KMP was on both Common Lisp and Scheme standard committees; Erik Naggum was an eloquent, if controversial, Lisp expert)
- tines 6y agoCorrect me if I'm wrong, but Lisp-2 vs. Lisp-1 has nothing to do with hygiene, it just splits Scheme's single problem (lexically binding values in macros) into two problems (lexically binding values in macros, and lexically binding functions in macros). The real problem, which Naggum includes, is the lack of GENSYM (if scheme indeed lacks it), and lack of first class symbols, as he mentioned.
- ska 6y agoIt's somewhat orthogonal, yes, but a lisp-1 just has more ways to run into the name collision.
- deckard1 6y ago> it just splits Scheme's single problem (lexically binding values in macros) into two problems (lexically binding values in macros, and lexically binding functions in macros). Bingo. Lisp-2 and GENSYM are attempting to solve the same issue in two different use cases. And, if I may add, GENSYM looks a bit lazy and half-assed next to the scortch-the-earth multiple namespaces of Lisp-2. It's like they blew up Lisp with dynamite and then sat down and said "whatever" when the same problem appears in macros. > The real problem, which Naggum includes, is the lack of GENSYM Guile Scheme has both GENSYM and DEFMACRO (unhygienic). I think quite a few Scheme systems err on the side of practical concerns. But that doesn't erase that fact that GENSYM is an ugly hack to get macros to work.
- varjag 6y ago> Lisp-2 and GENSYM are attempting to solve the same issue in two different use cases. Now this is… post-hoc, Lisp-2 is the original form of LISP and predates the concepts of macros. > And, if I may add, GENSYM looks a bit lazy and half-assed next to the scortch-the-earth multiple namespaces of Lisp-2. I would agree. However in reality we have a system that is half-assed vs a system that nobody likes to use.
- Jtsummers 6y agoAs an attempt at an answer: Unhygienic macros offer you more "power". With care, or another macro, you can express exactly the things you want with hygienic macros in a system like CL which lacks them, but the reverse isn't true. I cannot think of anything off the top of my head which would be particularly useful with unhygienic macros, but there probably is a use-case. My best guess (and just a guess) might be the SERIES and SCREAMER packages which redefine defun, but I could see it going both ways. A hygienic macro within the SERIES package would know the local definition and use it, but one from without would use cl:defun. With either hygienic or unhygienic macros this can create problems as in either case you may think you're using a particular defun when you're really using the other. NB: My CL macros are written carefully so they'd be roughly equivalent to the hygienic macros of Scheme, but with more boilerplate. At least when it comes to most variables, but I don't take care to ensure the functions used in my macros are not replaced in the local context where they're used.
- bjoli 6y agoI don't believe anything that can be written with unhygienic macros can't be written in a hygienic macro system. Macros written using implicit renaming is written just like CL macros, and with enough libraries you can do something similar with syntax-case. Heck, implementing an unhygienic defmacro over a regular lambda is something like 7 lines of syntax-case. In guile you could even use lambda* to get optional and keyword arguments.
- Jtsummers 6y agoSo, again, I don't think I know for certain why I'd want to do this, but here's an example of different behavior with the two: (defmacro my-not (x) `(not ,x)) (flet ((not (x) x)) (my-not 't)) In a hygienic macro system, that local definition of not will have zero impact on the execution. In an unhygienic macro system, that local definition is used instead of what the macro writer probably intended. That's a stupid, trivial example that would hopefully never be written. My best guess for wanting something like this, per my previous comment, would be a system like SCREAMER or SERIES which could make use of this local redefinition to produce a different-than-standard behavior. How would you write a hygienic macro which would make use of the local redefinition of not without also having to pass the redefinition to the macro?
- tines 6y agoThe unhygeinic part isn't as important as the fact that CL's macros (and other macro systems) are not simple pattern matching and substitution. But the lack of hygiene completes the circle for the concept that the program is simply a data structure, and macros are just imperative functions from syntax to syntax, and they can do anything that a normal function can do, like make HTTP requests. The destruction of the distinction between your code and the compiler, and the recursive relationship between the reader (and CL has reader macros, another dimension), macroexpander, and evaluator, is what is so mind-opening about lisp to me, and CL embodies that trifecta with the most ideological purity (imo).
- bjoli 6y agoIf you are arguing defmacro vs. syntax-rules you are indeed correct. The lowest common denominator of the scheme macro world is indeed a pattern substitution one (with hygiene). No procedure application at expansion time allowed. However, all schemes include a lower level macro system that allows you to break hygiene when you want to, most of them by asking explicitly (explicit renaming macro systems being an exception). r6rs, a standard that was disliked by some, standardises a lower level macro system called syntax-case that superficially looks the same as syntax-rules but gives you all the power of unhygienic macro systems (in guile for example, the old unhygienic defmacro is implemented using syntax-case. A very trivial thing to do, I might add). So, to re-hash: syntax-case macros are procedural. They allow for the full power of scheme at expansion time, and allows you to introduce bindings unhygienically using datum->syntax.
- deleted 6y ago[deleted]
- iainctduncan 6y agoThere are various hybrid schemes that support CL style macros. I'm using S7 myself, because embedding in a C host is what I'm after. I love it, it has support for CL macros with gensym and first class environments, and embeds easily in C.
- tines 6y agoWhat's S7? I've never heare of it.
- Jtsummers 6y agoA reference to this Scheme implementation: https://ccrma.stanford.edu/software/snd/snd/s7.html https://ccrma.stanford.edu/software/snd/snd/s7.html And from GP's own site (presumably, name is the same): https://iainctduncan.github.io/scheme-for-max-docs/s7.html https://iainctduncan.github.io/scheme-for-max-docs/s7.html
- iainctduncan 6y agoIt's a minimal embeddable Scheme created by Bill Schottstaedt at CCRMA, the Stanford computer music centre. it's similar in scope to Guile or TinyScheme (from which it was originally forked), and is linguistically similar to Clojure and Janet in that it is fundamentally Scheme, but borrows heavily from Common Lisp (keywords, environments, CL macros). It's mostly used in computer music projects (Common Music, Snd, Radium, and others), but not only - there are some folks on the mailing list who use it as an embeddable DSL for "regular" engineering projects too. I built Scheme For Max on S7, and have been very happy with the choice for my constraints.
- mac01021 6y agoWhat kind of applications do you want to build? What non-lisp languages do you usually work with? I think you will find that Clojure has the largest community and the widest use for commercial applications but, depending on your specific interests, either racket or common lisp could be a better fit. In summary, I think we need more information about your goals.
- vasergen 6y agoThanks, good points. I am working primarily with nodejs / typescript. So, yeah lisp is a totally different paradigm for me. In terms what want to build, backed and cli tools would be a good start for me.
- mac01021 6y agoI'm going to say Clojure is probably what you want. Via clojurescript, it has very good interoperability with the tools you're already using and it's possible that you might even choose to use it on the front end in the browser. That, coupled with the size of the community suggest to me that it is the winner here. For the (browser) front-end, there are lots of neat idiomatic-clojure libraries like https://reagent-project.github.io/ https://reagent-project.github.io/ For command-line scripting, your program will ultimately mostly access the filesystem or other OS functionality via interop with the host platform (either Java or Node).
- jnxx 6y agoIn that case, Clojure, ClojureScript, and Babashka ( https://github.com/babashka/ https://github.com/babashka/ ) is perhaps the best set of options for you. This are three implementations of the same language. Otherwise, and especially if you want to use C library interop, I'd suggest Racket. Racket is also relatively close to Clojure in philosophy.
- jnxx 6y agoI second that.
- reikonomusha 6y agoCommon Lisp with Emacs and SLIME if you want to do "ordinary programming" and want to really "feel" what Lisp is all about.
- Jtsummers 6y agoClojure - Learn this if you want a job programming in a Lisp family language. It's the most reliable one for achieving that goal. Good library support due to being hosted on top of other languages (like Java). It's an opinionated language, generally pushing the functional style and immutability. Scheme - Great amount of good learning materials. Smaller language, gets to the core of writing in both a lisp and functional style quickly. Pure Scheme code should trivially work across implementations. If you ever deal with external libraries your choice of implementation becomes more critical. Racket - You're using this already. Also a good language, and you can reuse the Scheme resources on top of it because it has language modes that are compatible with Scheme. Like with Clojure, you're dealing with a singular implementation so at least that choice is gone for you. Libraries should "just work". Common Lisp - Like with Scheme, implementation choice does matter somewhat. Multiparadigm, so you're a bit freer to choose how to implement your program (you can adopt a more procedural, functional, or OO style to suit your needs or wants at the moment). It's less opinionated than Scheme and Clojure. Some good learning resources out there, some of the Scheme materials translate well (in that they work) but don't teach good CL style. To answer your specific question: I first learned Scheme helping college mates who were a year or two behind me as GT switched to Scheme as its first CS course language after I took it. I really learned the lisp family with Common Lisp in grad school from an AI course that was using Norvig's Paradigms of AI Programming, and I kept using it as a hobby language ever since.
- iainctduncan 6y agoI think you should also add to Scheme: great for embedding a lisp DSL in another app. Scheme's minimalism means there are a number of excellent options for working this way. I use S7 myself.
- Jtsummers 6y agoProbably, but it's not an option at this point. There's a 2 hour edit window on comments.
- iainctduncan 6y ago
- samvher 6y agoI started with SICP to understand Lisp conceptually (it also taught me a lot about abstraction). Then I worked through Practical Common Lisp to learn the ecosystem a bit better and programmed some tools for my own tasks. Finally I worked through “Write yourself a Scheme in Haskell” which deepened my understanding and actually ended up with me spending more time with Haskell than with Lisp (it was a gateway drug to more structured functional programming). Overall this sequence was a very satisfying experience and I now find myself spending most of my time with Erlang which feels a bit like middle ground.
- filoeleven 6y agoA note on Clojure: it’s a lisp but the language has some important differences from (all?) other lisps that are inherent to its design. The two key changes are immutability by default and the sequence abstraction[1], with syntax differences being a close third. Sequences in particular mean that some pretty fundamental lisp functions don’t operate the same way. There are two ways to look at this. One is that they encourage better coding practices, the other is that they are restrictions that diminish the power of the language and make you jump through unnecessary hoops to get stuff done. Basically, “guard rails” vs “training wheels.” I can’t say much more since Clojure is the only lisp I have played with (and I don’t see this changing, I quite like the language design). Code written in Clojure is not trivially portable to other lisps, and vice versa. I think there are differences in what you can do with macros too. No value judgment here, I just think it’s important to know that these non-trivial differences exist when choosing which language to explore. [1] https://clojure.org/reference/sequences https://clojure.org/reference/sequences