I’ve never did anything serious with Common Lisp, but my light experience on it was that
- the idea that almost all language constructs are user-implementable with macros is quite impressive (but I don’t buy the argument that “real” macros are only able in s-exprs)
- and the REPL-driven development model was a really beautiful and seamless experience.
But… every time I try to use it on some code, I find too many warts and inconsistencies that I just didn’t want to spend too much effort in making it work. It’s a beautiful language in it’s own ways, but the other parts are too ugly (to me, of course).
I’m fine with it being a lisp or not; I just want a clean language with macros baked in (and becomes the basis of most language features), and with a REPL-driven development model as a first class citizen (with interactive restarts and all).
Unfortunately it seems a pipe dream… so I’m stuck here.
I don't like REPL driven development. REPLs are celebrated as some sort of achievement in interactivity, but they're hopelessly puny, barely imitating a UNIX shell.
When I write Emacs Lisp, I don't have a REPL. I just put point at the end of a random s-expression in a random Emacs-mode buffer, hit C-x C-e, and it gets evaluated. Or I do "eval-print-last-sexpression" to get the output on the next line. If I put my emacs in an org-mode code block, I'll get the output nicely formatted by org-mode. I can get close to this in Common Lisp with SLIME, but I've never found it as tight as Emacs Lisp.
But Emacs lisp is still puny. Common Lisps had much higher aspirations than SLIME and a crappy UNIX-based Lisp executable. Allegro and Lispwerks still run on the philosophy that your IDE is just some live code in your lisp image, and you extend that image via the GUI. The same philosophy pervades (non-GNU) Smalltalk implementations.
This is the sort of thing that still makes Lisp (and Smalltalk) absolutely stand out among programming languages, and it will be a crime when it is inevitably forgotten and we are left dumbfounded by the banality of REPL driven development.
> When I write Emacs Lisp, I don't have a REPL. I just put point at the end of a random s-expression in a random Emacs-mode buffer, hit C-x C-e, and it gets evaluated.
That actually is repl driven development. It does not mean that you type everything in on a repl prompt. It means you interactively and incrementally work on a program.
Also, unless their configuration has changed things, C-x C-e will print out the results in the mini buffer at the bottom. So it retains each of the read, eval, and print parts of the read, eval, print loop. And since the program doesn't terminate (unless the expression you provided causes that), you're still in the loop part until you close emacs.
Allegro CL and LispWorks have very capable REPL experiences. They provide a mostly object-oriented implementation of Common Lisp with excellent support for the Condition system to interactively deal with errors, including hierarchical debug break loops and source level interpreters.
Didn't know about that, although I have been using Emacs for over ten years! Tried `M-x ielm`, `(help) RET`, wow! Will explore it. Been only using the scratch buffer and `C-x C-e` to evaluate sexpressions.
I wish GNU Emacs had better introspection, It's probably because it values user experience more but it saddens me when I see "You shouldn't use this from a lisp program, it's intended for users" or something like it. I understand the reasoning but having seen the power of introspection in Symbolics Genera makes me long for an Emacs that makes Elisp as much a feature as "Text-editing/browsing/etc".
I wonder how difficult it would be to port elisp to Common Lisp and then get GNU Emacs running hosted in SBCL or whatever. I really like the idea of my editor running in the image.
If you just mean writing an implementation of Emacs (or something Emacs-like) in Common Lisp, that's not very hard, and it's been done a few times. See, for example, Lem[1] and Hemlock[2].
Heck, I wrote one for MacOSX in about 2001 or 2002.
If you mean a drop-in replacement for GNU Emacs, that's a lot harder. Besides the UI and the editing infrastructure, you need to write a bug-compatible implementation of GNU's elisp, or you lose the whole GNU Emacs ecosystem. That ecosystem is most of its practical appeal. That's a whole bunch of work.
It's been done in the form of an Emacs clone called Hemlock. Lispworks uses it for their IDE although they don't make enough of the source available to fully customize it. Clozure Common Lisp also uses Hemlock for their IDE on the Mac and its source is all in the box.
I don't think that's exactly what you asked, however, and I agree that a true Emacs running entirely on CL would be preferable.
Source code of LW editor is mostly available. I’ve done some extensive modifications to it (implemented VIM mode), but these days I’ve moved back to Emacs- just something I prefer more
> (but I don’t buy the argument that “real” macros are only able in s-exprs)
There are macros in non-s-expr languages. Usually then one needs to manipulate an AST data structure. That has consequences in those cases:
a) the macro forms need to be parsed according to a syntax, usually a predefined syntax
b) the AST data structure adds some complexity, which makes simple things more complex, but can also be a help
For Common Lisp a) means that the code enclosed in a macro does not need to conform to a predefined syntax and the macro is responsible to parse it. A typical example is the LOOP macro: (LOOP for i from a to b by 2 when (> a (foo b)) maximize (sin b)). That's a whole different sublanguage, which does not look like the typical nested lists based notation. It uses symbols as syntactic words in a complex syntax, which otherwise would not be valid Lisp.
You can see what it does: one can add arbitrary syntax. Which is good and bad at the same time.
b) means for Common Lisp that there is certain meta-level model, where the language can be used to program itself via procedural macros. Now one has to deal with code, where one can program on a meta-level which looks like the normal level. That's also good and bad. Good because one can apply all the knowledge and tools on the meta-level, too. Bad because it means that a programmer may see in a debugger code-generating code and the programmer sees code constructs which have code generators behind it. In a Lisp interpreter (one which processes Lisp source code at runtime), this will also be visible at runtime. In a language which uses AST data structures, the code in AST representation looks very different from the written code. In Lisp the code as data looks the same as the written code.
The experience is widely different from programming in other programming languages and not that easy to learn: programming a language on a meta-level in itself.
Most programming we see seems to happen without that self-programmability capability.
> but I don’t buy the argument that “real” macros are only able in s-exprs
Metaprogamming can be done also semantically in other languages. Elixir for example has also macros and a good part of the core of the language is written with them. When writing a macro you then get an AST in input (represented with tuples in Elixir) and give another AST as output. I think Rust has something similar.
The reason why s-exps are better to write macros is that the AST has the same form has the code you write in the editor. This way textual code and code as data have the same representation, making it easier to reason and manipulate the code.
I don't necessarily recommend it as a general purpose language across many uses right now, but I've been working in lua a lot and fennel has really impressed me.
It only adds special forms and doesn't change the runtime semantics at all, so you can drop it into any lua runtime for a strictly better dev experience, or target luajit or whatever but that's not relevant to me.
I haven't used its macro system yet but it looks fine and pretty much like clojure's. I only ever wrote a handful of macros over years of working in clojure so ymmv anyway. Also it has pattern matching, which is ridiculously powerful and smooth in lisps, and it still boggles my mind that clojure doesn't seem aware of that.
Again I haven't used this language yet for anything that didn't require lua, so I'm not sure how that'll go. I'll definitely consider it next time I need a lightweight scripting language though.
Clojure doesn't need JVM. You can run it with GraalVM either directly [1] or via Babashka [2]. Both are great options for get into Clojure since there's almost no startup time like JVM and you don't have to be burdened with learning and heaviness of JVM stack.
"Other implementations of Clojure on different platforms include:
- Babashka,[82] Native Clojure scripting language leveraging GraalVM native image and Small Clojure Interpreter.."
I guess you mean that some particular implementation of JVM isn't needed. But in general Clojure has "j" in its name, it wouldn't make sense without JVM at all.
No, you don't need GraalVM either, it is only built with GraalVM, but it is usable as a single static native binary with no other dependencies.
Think how say CPython needs GCC to build itself, but to use Python as a user you don't need GCC, only the compiled CPython interpreter.
This is the same for Babashka Clojure, you only need GraalVM to build it, but as a user you only need the compiled Babashka interpreter.
There's also Self-hosted Clojurescript which only needs a JS VM. And there is Clojure CLR which only needs a CLR VM. And you've got Clojerl that only needs BeamVM.
But Babashka is probably the one you'd want to try, since it is dependency free, just download the binary and put it on your PATH.
This does seem cleaner. I have some questions though:
- What about the interactive environment like the one in Common Lisp? It's not enough to only have a "REPL", I think.
- There are so many Lisp dialects. Is this one going to remain obscure?
- What's the library situation?
>What about the interactive environment like the one in Common Lisp?
Never used a "real" Lisp REPL, but Conjure[0] seems like it ticks a lot of boxes.
>Is this one going to remain obscure?
There are only a ~dozen mainstream languages. Once you get outside of the popular zeitgeist, you have to appreciate exactly what you are getting. It takes a lot of dedication to become fluent in a language/ecosystem, so it is no surprise that people are reluctant to switch to a novel platform. Clojure is far more likely to ever become mainstream (owing to the huge JVM ecosystem), but even that seems to have only limited industry penetration.
> (but I don’t buy the argument that “real” macros are only able in s-exprs)
The Rhombus project in Racket^1 is an attempt to fix a lot of things about Racket and S-exprs but one of the goals is creating a syntax that is able to be manipulated as easily a s-exprs.
> By “macro-extensible,” we mean that Rhombus users should be able to extend the syntax of Rhombus in much the same way that Racket users can extend the syntax of Racket. Complex syntactic extensions such as object and class systems, static type checkers, and pattern matching should be implemented as libraries while still providing a surface syntax familiar to users of these features in other languages.
> The surface syntax is responsible for some grouping, but not all. This requires that the parser understand the program’s bindings and expand macros to get a complete picture of a program’s structure. Interleaving the parsing of a token stream with macro expansion in this fashion is called enforestation, and it allows macros to extend the syntax of conventional languages. The Honu research language pioneered this technique.
Many languages have support for REPL driven development (Haskell, F#, …) It isn’t unique to LISP. Remember Basic programming on the old C64/ZX Spectrum computers? REPL driven development :)
I disagree. I think it’s useful to distinguish repl-driven development from development that merely has incidental access to some kind of repl. That’s the topic of this blog post:
Good to see, but at this point in its lifecycle I don't really believe a lack of good tutorials is a barrier or even impediment for CL.
The problem is after the tutorial is done, all the libraries (look (like (this))) and the language is so powerful it is difficult to know if this 10kb contains a life-changing insight into the nature of programming or a half-hearted implementation of half of something that was a bad idea to start with. Knowing the syntax and technical semantics of the language doesn't help with that.
The topic has been done to death, but the lisps seem to have a social organisation problem that the community never quite managed to get a grip on.
Glad to see this old horse is still being pulled out and beaten every now and then.
I think this is the worst part of learning to program in CL: the self-flagellating, cynical CL users and the haters that parrot this old, barnacle-ridden trope: it's too powerful! Macros! Nobody can understand it but gods and strange people on the Internet! You will have to listen to these people constantly invade every forum, discussion group, and chat room on the Internet to tell you how you shouldn't be learning CL.
I like powerful languages. They have neat ideas. If they help you get more done in less time with less code, great. Not every software project needs to be a tedious, boring slog that takes 30 developers 8 months to do what you can with CL in a week.
Keep learning CL if that floats your boat. I had a blast learning it and it's a great tool to have and a constant source of inspiration for ideas.
> the haters that parrot this old, barnacle-ridden trope: it's too powerful! Macros! Nobody can understand it but gods and strange people on the Internet! You will have to listen to these people constantly invade every forum, discussion group, and chat room on the Internet to tell you how you shouldn't be learning CL.
These people are actually the reason I went and learned CL. I couldn't understand why some programmers would hate a programming language so much. Now it's one of my favourite languages.
Yes, it's great to experience the 10x or 100x developer syndrome sometimes.
Using Clojure changed my life somewhat, as at some point I rewrote 2000 lines of C++ (to handle splitting and coalescing NAESB cycle pipeline nominations) in about 27 lines of pattern-matching Clojure, and just no one, no one would take it seriously. A usable UI in Swing to manage it wasn't much more, and was cross-platform. Not a fun experience overall, I ended up quitting that company, doing iPhone dev for a bit, then moved back into G&G.
Other than that rewrite experience, I just used Clojure like I used to use Perl. Easy to bang something out in, and performant native Java libraries for things you might not expect, like low-level SQL Server (2005 at the time!) and Oracle (8 at the time) drivers.
I'm back mainly as a C++ developer now in visualization and HPC.
That's also the problem with Lisp (and other powerful languages). They are far too malleable. They can be changed into unrecognizable blobs by people with lots of intelligence but low wisdom (I include myself in that group).
They don't _have_ to. They can lead (and often do) to clean implementations. But we tend to like 'cleverness'. The larger the team, the more detrimental the effect.
That's why we ended up with Java. And more recently, golang. As much as I like Go on its niche, it's a straightjacket. I'd often think to myself "this whole file I've been working for a week on would be 5 lines of scheme or lisp". But then if I get run over by a bus the company could theoretically replace me the next day (they couldn't because there's far more knowledge required than coding, but they think they could).
Ah yes, the "we should be able to hire anyone off the street and replace you instantly," fallacy. I've never in all my career ever been asked to walk out into the street and grab a random stranger and pull them into our office to fix this code now because Jerry just got hit by a bus and won't be making it into the office ever again. We can barely hire other programmers.
Mediocre programmers will write unrecognizable blobs in any language, and good Lisp programmers can use macros and other advanced tools to make their code even more clear and understandable.
To be fair, I've seen much bigger unrecognizable blobs in Java than I have in any Lisp. A language that's too rigid just makes people reach for other workarounds, e.g. craziness in the build system, using lots of reflection, configuring things with XML, etc. It doesn't make it any easier for someone to come into a project and understand what's going on. At least with Common Lisp you can just expand the macros to see what's going on.
If you’re unfamiliar with Common Lisp, it’s important to understand that it’s a multi-paradigm language. The presence of closures, key functions in the standard library, and the syntax often push you naturally to a functional solution. But you shouldn’t feel bad about writing a LOOP that mutates a bunch of state under the hood. This isn’t scheme!
> But you should feel bad about writing a LOOP that mutates a bunch of state under the hood.
I think you omitted a word there: one should not feel badly about writing a state-mutating LOOP. That's okay, and often the best solution to a problem.
Heck, I wrote a state-mutating TAGBODY just yesterday …
Practical Common Lisp gets you up to speed very fast.
I wish there was something similar for scheme. Most scheme books focus on teaching you compsci with the language and not on teaching you how to build practical things with it.
It's quite hard to onboard someone to a scheme codebase, despite scheme's reputation of being a simple language.
The Little Schemer is a great book but it's in no way practical and very much focuses on teaching you comp sci - it's been a while but IIRC doesn't it culminate in constructing the Y combinator?
Realm of Racket [0] seems like it might be more OP's speed.
Maybe things have changed over the years. I've played around with Hy in 2017 and in the end felt like it combines the bad parts of Python with the bad parts of a Lisp.
If you're forced to use Python it's usually because of one of 2 reasons: Either you need to work with colleagues on something (in which case almost certainly they wouldn't accept a lispified version of it) or because you need some of the libraries that are already implemented.
In the latter case, you might say Hy is a good option. But why bind yourself to the slowness of Python when you could just as well use some fast Lisp (e.g. Common Lisp) that interacts with a Python interpreter similar to nimpy [0] from Nim? Not sure if such a thing already exists for CL, but it should be quite feasible to write and then you get access to all your Python library needs while actually using a better language for the rest of your code.
But I'm all ears on the real advantages Hy provides aside from being neat.
For me the sad thing was that there is no equivalent of let, progn and so on. It really felt like Python with a funny syntax (plus macros).
I'm not lisp enough to make a macro, but supposedly, isn't let under the hood making a lambda function and calling it? That's within the confines of possibility in Python.
I suppose Hylang is quite slow (and possibly has leaky abstractions). Ideally the main C/C++ libraries like libtorch should be wrapped in Common Lisp and not Python.
Rabbibotton has created the CLOG framework and it is fantastic. It supports a full desktop gui experiences over websockets all the way down to static webpages and any combination in between that you could want.
It’s really impressive work. I guess it’s a reimplementation of a framework he wrote in ADA years ago, so it’s really well developed and thought through.
One of the salient features of Lisps is that they are dynamic languages designed so they can be compiled into very efficient code. The details of how this works are interesting (for example, the use of low order bits as tags to efficiently detect common error cases, and also to allow types like characters, fixnums, and some floats to be represented without allocation.) A downside of this is that lisp implementations may not be ABI compatible with other language implementations.
The macros are orthogonal to this. Macros are really just an example of a more general thing: features that are used to effectively implement parts of the language definition are often lifted up and also made available to users. This effectively allows the language to be extended in a way that very closely resembles the language's built-ins. (This is not always the case; lifting more such things would be a good avenue for extending Lisps.)
Looking at its use, you might think it lets you declare types of things for type-checking purposes. i.e.
(the integer (operate-on 1))
... would make the program assert-fail if (operate-on 1) were somehow not an integer.
The real story is it can do that, but the spec actually says behavior is undefined if the value is not the specified type. So check-failing is one of the many things it's allowed to do.
In practice, depending on your compiler settings, `the` can act like asserts or it can act like places the compiler's allowed to paint racing-stripes on your code to make it go faster by skipping dynamic type checks and letting data structures mangle up if the types are wrong. ;)*
I tried to google it, but I only found some shit I have written myself. First thing I did with my very own Symbolics-machine, was to implement explode & compress, because I did not want study those marvelous string-manipulating possibilities it may have.
Compress & Explode manipulate of list of numbers, of course. In my latest Brain-Fart production I think have finally solved all problems. List of numbers, whose first number is 34 aka \" , is printed as "string" in ppretty-printer and editor. No need to implement strings *EVER*.
What are people using LISP for? Other than the Emacs flavor, and some companies using Clojure, I'm not really sure what I'd use it for? Would I use it to replace Python or Shell scripting for my custom CLI tooling? Anyway, I've seen a lot of people talking about the Lisps lately, and trying to figure out what I'm missing.
I've used it for a lot of stuff over the years: a constraint-based GUI framework, a knowledge-based automated testing system that ran tests remotely on fleets of target machines, a model-building-by-demonstration system for the aforementioned testing system, an experimental operating system for Apple hardware, a direct-manipulation rapid-application-development system, a WYSIWIG programmable word processor, an artificial life simulator, a help and online-documentation compiler, a commercial graph database, a full-stack embedded control system with GUI for a forensic fingerprint-scanning machine, a syntax-aware diff program for code, a series of name and vocabulary generators for use in fiction and games, a list manager, several versions of a Lisp interpreter and compiler, a file-browsing program, several games, a knowledge-based machine-control program for laser-sintering machines, an anomaly-discovery system for various kinds of data, and a radar image analysis and classification system.
Plus a whole bunch of supporting libraries, tools, and random toys.
I've used it in preference to anything else since 1988. Lisp is an exotic niche option in the programming language space, so a Lisper needs to be prepared to work in other languages, and I often have. I've been fortunate, though, in that I've been able to work mainly in Lisp for more than half my career since 1988. I use it every day in my current job (working on the radar stuff and some other projects at the same employer).
Truth is lisps don't have a whole lot of market power. I use CL for medium size scripts and CLI tooling, as well as a lot of tools which need to do a lot of crunching but don't have any significant UI component. I wouldn't wish my codebase on my worst enemy, but the libraries I've built up fit me like a glove, so it's perfect for rapid coding only I need to deal with.
Hint: all Quantum computing companies, Google for ITA Software, the NASA for James-Webb's planning and scheduling system, smaller companies (Kina), solo devs that find they are more productive than in Python (like myself).
The only Lisp I know of is Emacs Lisp. I thought It was implementation of common lisp, but according to Wikipedia I am wrong.
So If primarily Linux user (sysadmin/devops/ occasional embedder programmer), wanted to learn lispy like language, that is useful which one would you pick?
The idea of using Emacs lisp for scripting was introduced to me he on hacker news, and it's not a bad idea. In service of being a good extension language, Elisp has a lot of really handy built-ins. There aren't a lot of Elisp language extensions, but you can often pluck good functions and macros from existing packages. For scripts with more than a few lines I like to use CL, but that's after building out a pretty large utility library specifically for the task.
I’m not sure I’d call CL lightweight. It’s a large language that also has some very interesting gaps in the standard. It is possible to write very performant code with modern implementations though. One of my favorite examples is the regex library cl-ppcre. Thanks to the nature of Lisp, the recognizer for each regex you create can be compiled to native code on compiler implementations of CL.
And as a practical matter if you want to learn Common Lisp you’re probably going to be using GNU Emacs. Thus you’ll probably end up picking up some Elisp too. Both have their share of idiosyncrasies, but a great deal of what you’ll learn applies to both.
> One of my favorite examples is the regex library cl-ppcre. Thanks to the nature of Lisp, the recognizer for each regex you create can be compiled to native code on compiler implementations of CL.
That is not true - cl-ppcre generates a chain of closures. Experimental performance is in the same ballpark as typical "bytecode" interpreting regex implementations.
However, the "compiler macro" feature in Common Lisp allows for generating the chain of closures to be performed at compile-time, and invalid syntax (in string literals) can be detected at compile-time.
the binaries are not specially lightweight either. What I had in mind in that when you start CL or install a bunch of dependencies (by staying in the REPL), this doesn't take many resources. Try another modern Lisp and bam, CPU and memory on fire. Running a binary is instantaneous too. That's a smooth developer experience.
Dude, incredible work. I've only discovered CL in the last couple of months and everything I learn and discover brings me so much joy after being solidly disillusioned with programming after a decade-ish career. The first page of your tutorial cracked me up and a quick glance at CLOG has blown my mind. I can't wait to dig into it all.
This is a great idea - I'm looking forward to trying it.
One nitpick: the Google Docs code does not display favourably on mobile. It might help to publish in HTML if you're interested in targeting those readers.
Rabbibotton is really motivated and putting in a lot of effort with CLOG and with these tutorials. I think he's even offering monetary rewards for others to write tutorials. Its nice to see his efforts make it to the front page here. :)
“LISP is worth learning for a different reason — the profound enlightenment experience you will have when you finally get it. That experience will make you a better programmer for the rest of your days, even if you never actually use LISP itself a lot.”
Honestly, "just because I want to" sounds like a more compelling argument than talking about enlightenment. Mainly because the latter implies that people who don't know lisp are somehow unenlightened or lacking in some way - that comes across as really arrogant and it's clearly false since there are many successful and highly skilled programmers who don't know or care about lisp.
I kind of agree with the GP comment - nobody needs to learn lisp. The main reason to learn it is some personal interest or curiosity.
There is some enlightenment experience, when you get it. This it is when one figures out why Lisp is how it is: a language programmed in a data structure, programmable in itself. One can live without that enlightenment. One can also live without understanding recursion, but it was a small enlightenment for me when I understood recursion and how to use that in programming. There are a bunch of enlightenment experiences one can have. I had another one when I first read the Smalltalk books and later saw a Smalltalk system - I thought that was the end of programming, everything was done.
Alan Kay (the 'Alan Kay' of OOP and Smalltalk ) had an enlightenment experience with Lisp:
"AK Yes, that was the big revelation to me when I was in graduate school—when I finally understood that the half page of code on the bottom of page 13 of the Lisp 1.5 manual was Lisp in itself. These were “Maxwell’s Equations of Software!” This is the whole world of programming in a few lines that I can put my hand over."
> false since there are many successful and highly skilled programmers who don't know or care about lisp
Still they unknowingly may use a lot of things that were once pioneered in Lisp, like these: conditionals, functional programming, managed memory and garbage collection, evaluator/interpreters, read-eval-print-loops, image-based programming, ...
> when I finally understood that the half page of code on the bottom of page 13 of the Lisp 1.5 manual was Lisp in itself
Even histories of Lisp often don't emphasize this: Lisp was not, originally, invented as a programming language. It was a notation for describing the mathematics of computation. A variant of lambda calculus that could describe itself compactly.
The fact that eval could actually be implemented, was an accidental discovery. To quote McCarthy:
> Steve Russell said, look, why don't I program this eval ... and I said to him, ho, ho, you're confusing theory with practice, this eval is intended for reading, not for computing. But he went ahead and did it. That is, he compiled the eval in my paper into IBM 704 machine code, fixing bugs, and then advertised this as a Lisp interpreter, which it certainly was.
it was developed as a programming language from day one. It just had no such evaluator, until they came up with the idea and implemented it. There were Lisp programs already before that.
> Mainly because the latter implies that people who don't know lisp are somehow unenlightened or lacking in some way
But if you haven't learned Lisp you are absolutely lacking in some way as far as understanding programming languages. One obvious example is don't really understand what the url of this website is referring to (though I do suspect a huge number of today's HNers have never implemented the y-combinator).
To be clear, you can be an excellent software engineer and never touch or understand lisp, but if you are seriously interested in programming languages you really are missing a major part of picture if you don't know a lisp.
Anyone who is seriously interested in programming, beyond just creating software, absolutely must have experience in a lisp. It's completely fine if you aren't interested in programming other than solving a specific problem, but the idea that "nobody needs to learn lisp" is false.
The several important things about lisp that you won't find in other languages without learning lisp include (I'm considering all lisps here, including schemes):
- it's essentially a working implementation of the untyped lambda calculus, an essential model for thinking about computing outside of the Von Neumann architecture.
- It is a symbolic programming language which allows for unique ways of manipulating code as data. The only other programming language that I know of that offers symbolic programming to the same degree is Prolog (outside of computer algebra systems).
- The parens and prefix notation really are a powerful feature, despite being off putting to beginners. You are essentially programming an Abstract syntax tree. All programming language spend some of their time in this form, you just don't usually get to play with the code this way. This makes it incredibly easy to prototype ideas for languages and compilers in Lisps
The functional programming and meta-programming benefits naturally fall out of all of these. The reason metaprogramming is so powerful in Lisp is because of a combination of writing code in a tree structures and being a symbolic programming language.
The big picture reason that lisp is so great for people interested in better understanding programming is that it is a language that encourages you to write domain specific languages to solve your problems.
I'll be the first to admit that this is not great for real world software engineering, but if you want to understand programming better, it is essential.
I've found more recently I want to solve problems with domain specific languages, so I'm totally on board with that. I would say that making dsls to solve problems is a great way to engineer software, as the code is usually testable and you don't need to modify it. Sort of where functional programming meets solid. Maybe not the best approach if you're in a startup though.
Sounds like you understand the pros and cons of DSLs: If you have a high functioning, disciplined software engineering team, a good DSL can smoke your competitors. If you don't have such a team, a DSL can smoke you.
This is a very common argument. It's true that Lispers sometimes come across as arrogant but that's because of the asymmetry inherent in evaluating programming language power. Paul Graham calls it the Blub Paradox.
Another reason to learn Lisp is that it’s been around for over 6 decades. Algol 60 is the only other language from that era that I can think that still strongly influences contemporary practice. Since all of Algol’s descendants have felt the need to introduce their own syntactic novelties, contemporary Lisps feel considerably closer to the parent language.
The Lindy effect means that the odds are very good that if you do learn Lisp it will remain relevant for the rest of your life.
Perhaps not, but need is not the only reason to learn; people also learn things because they are fun, pleasurable, interesting, challenging, entertaining, beautiful, revelatory, creative, inspiring etc. It'd be a dull life if we only learn what we need to know.
Even though Common Lisp isn't used widely it never hurts to learn new things (especially when those things can be quite different than what you normally use).
I'm a software engineer interested in getting more productive at my job, which namely involves the current React/typescript ecosystem. I have no interest in lower-level programming as a career path.
What benefits would learning Lisp provide me so that I "Need" to learn it?
I read the defmacro link and found it very interesting and cool; but I still feel as if I'm missing what makes this so earth-shattering? Do not get me wrong - it is insanely cool and wonderful to be able to modify lisp's syntax with lisp... but it just seems like that... it's cool. I don't see why this would be any different than defining a function like I normally do.
Sure, I can create an entirely new operator that becomes valid syntax, like `*` which creates an exponential operator. But why is this more productive than simply defining a "exponent()" function or something similar?
It seems also that tech debt would accrue incredibly fast as joining a lisp codebase would require learning almost an entirely new set of syntax. I'm sure I 'm missing something, but I can't see at all why I need to learn LISP. It's cool, neat, and wonderful... but that's about it from my understanding.
It's not easy to get the point across just by reading about it. Id honestly say you should just learn some lisp and implement something cool.
> I don't see why this would be any different than defining a function like I normally do.
Because with functions you don't define any new syntax or implement a DSL; you don't have access to the compiler during read, compilation, and run time. This allows you to easily extend the language: do you miss list comprehensions from Python? Add it yourself with a macro. Want to generate boilerplate code? Macro. Prolog compiler? Yes. Basically anything in this book: https://github.com/norvig/paip-lisp
> But why is this more productive than simply defining a "exponent()" function or something similar?
Those aren't necessarily incompatible. Nobody can avoid linear algebra, but almost nobody actually needs to use or know linear algebra. Heavily symbolic fields like math are probably not great examples though - different methods can be used to reach the same results because it's all fundamentally the same, just differing representations.
- the idea that almost all language constructs are user-implementable with macros is quite impressive (but I don’t buy the argument that “real” macros are only able in s-exprs)
- and the REPL-driven development model was a really beautiful and seamless experience.
But… every time I try to use it on some code, I find too many warts and inconsistencies that I just didn’t want to spend too much effort in making it work. It’s a beautiful language in it’s own ways, but the other parts are too ugly (to me, of course).
I’m fine with it being a lisp or not; I just want a clean language with macros baked in (and becomes the basis of most language features), and with a REPL-driven development model as a first class citizen (with interactive restarts and all).
Unfortunately it seems a pipe dream… so I’m stuck here.
[0]: https://mikelevins.github.io/posts/2020-12-18-repl-driven/