15 ms·
Understanding the Power of Lisp (2020)
- phoe-krk 5y agoThe thing is that trying to understand "the power of Lisp" via the toy interpreter from The Roots of Lisp[0] is like trying to understand "the beauty of the sea" after seeing a single five-minute YouTube video explaining it. It will give you the basic idea, but it won't tell you about macros, reader macros, compiler macros, and having the whole language always available to build your abstractions on; it won't tell you about CLOS, including multiple dispatch, metaclasses, or method combinations; it won't tell you about the condition system and programming from inside the debugger; it won't tell you about live recompilation and live coding; it won't tell you about the JVM interoperability of Clojure, Kawa, or ABCL; it won't tell you about Racket's tower-of-languages approach to programming; I can keep on going for a while. And, since most Lisp dialects and implementations are nowadays compiled, either to native code or to bytecode, the just-interpreting approach doesn't even work very well. Articles like this are fun, but they end up completely missing the point. This isn't "the power of Lisp"; it's just the very, very, very beginning. The rabbit hole goes much deeper. [0] http://www.paulgraham.com/rootsoflisp.html http://www.paulgraham.com/rootsoflisp.html
- agumonkey 5y agohere's how to leverage the pretty printer to transpile lisp into pascal https://merl.com/publications/docs/TR93-17.pdf https://merl.com/publications/docs/TR93-17.pdf
- phoe-krk 5y agoTIL. This is cursed. Have an upvote.
- agumonkey 5y agoHey, I didn't even realize who I was answering to. Btw there's a part 1 online too https://merl.com/publications/docs/TR91-04.pdf https://merl.com/publications/docs/TR91-04.pdf
- phoe-krk 5y ago> Hey, I didn't even realize who I was answering to. The best kind of comments are the ones which respond to the what as opposed to the who. :D
- deleted 5y ago[deleted]
- gumby 5y agoThat’s hilarious to me because I remember someone at UT wrote a pascal compiler in Lisp so TeX would run on the lispm.
- p_l 5y agoSymbolics provided Pascal, Prolog, Fortran 77, C and I believe Ada (but I never seen that one) implementations that used ZetaLisp as intermediate language. The Pascal one was used to build TeX, indeed.
- rmbyrro 5y agoI've learned Clojure. Tried and failed to see this unique power of macros. Truly asking for help: can you help explain what can I do with macros that I cannot do with functions? Or, maybe, cannot do with high quality or low complexity using functions?
- deleted 5y ago[deleted]
- mwattsun 5y agoMy impression, and I hope I'm wrong, is that macros and meta programming were powerful ideas 30 years ago, but now most modern languages have generics, template meta programming [1] and reflection. I'm a curious amateur and probably out to lunch, but there you go. [1] Some other languages support similar, if not more powerful, compile-time facilities (such as Lisp macros), but those are outside the scope of this article. https://en.wikipedia.org/wiki/Template_metaprogramming https://en.wikipedia.org/wiki/Template_metaprogramming
- bcrosby95 5y agoThe existence of template metaprogramming is an argument for macros, not against them. It shows the lengths to which programmers will abuse and misuse a feature so that they can reach their goals.
- mwattsun 5y agoWhen I first started writing asm code, it was accepted to write self-modifying code (programmatically create new code, then jmp to it.) Then I discovered and was told it was a bad idea. So that's how I view Lisp macros - creating code on the fly and executing it. When I was studying this issue, I came across femtolisp, which is a standalone Lisp by the author of Julia, Jeff Bezanson. Julia has metaprogramming so I wanted to look at it. In this video [1] Professor Steve G. Johnson explains metaprogramming (around 10 min mark) and says "most of the time, don't do metaprogramming." He points out in the base Julia there are 36,798 methods, but only 138 macros and 14 generated functions (.04% of the code), so I have the impression it is still frowned upon. [1] https://www.youtube.com/watch?v=mSgXWpvQEHE https://www.youtube.com/watch?v=mSgXWpvQEHE
- joshtbradley 5y agoAuthor here, that's an apt analogy. Perhaps it helps to understand where I was coming from; I had never written a line of LISP and was struggling to fully grasp the power that Paul Graham had hinted at. So I started at the beginning, and although it was just the brim of the rabbit hole it certainly opened my eyes. And I hope it can help other beginners open their eyes as well. I plan to fall down the LISP rabbit hole one day, and continue this series in full detail.
- mark_l_watson 5y agoWhile I don’t disagree with Josh’s blog, concentrating on just language features leaves out the style of Lisp development: bottom up REPL style development. When I have to use Haskell or Python, I find myself working as if I were using Lisp: I still favor the REPL and building up from primitive functions to the top level application. This is probably a bad habit but it is the way I work. BTW, using the standard Emacs support for Python works very well: load a file, then re-evaluate just changed classes and functions (not Lisp, but a good work flow anyway).
- convolvatron 5y agodo you struggle with bottom-up-Haskell? I always associated Haskell with a very opinionated top-down process
- mark_l_watson 5y agoI like Haskell, but my Haskell skills are weak. I experiment in the REPL to see what works and then write functions in an editor. Also, I like writing pure Haskell code, and when I need to do network or file access, etc., then I find appropriate code on the web that I can learn from. So, my use of Haskell is fairly simplistic. I even wrote a very short book using the small subset of Haskell that I am comfortable with and use for my own projects.
- exdsq 5y agoWhen I worked in Haskell I always found a type-driven top-down approach helped me work out what I needed to do literally starting from something like App :: Input -> Output Out of interest where are you working such that you're using Lisp? Pretty sure I've actually asked you before ha, but can't remember. Every-time I get burned out with frameworks and polygot development I end up daydreaming of using a stable language like common lisp for the remaining ~40 years of my career.
- mark_l_watson 5y agoI have used Common Lisp for a ton of paid work since 1982. That said, in the last 7 years people have paid me to do deep learning work, so that work uses Python. Follow the money. I am deeply bound up in Common Lisp because of my history. However, if I may make a suggestion: you might want to take a careful look at Racket: easy to make standalone apps, good libraries, large community, and if you don't like Emacs, the Racket IDE is really pretty good. Sit in on one of the online Racket conferences to see many kinds of cool applications and libraries people use Racket for.
- vincent-toups 5y agoI'm programming in Lisp (Chez Scheme) now. I've been a serious Lisp programmer (recreationally and sometimes professionally) for around 10 years and I have programmed in Common Lisp, Scheme, my own weird dialects, Emacs Lisp, etc. At this point I feel like almost everything written about Lisp is silly. Taken as a language family as a whole, there isn't much that separates Lisp from most of the other languages that are out there _except_ syntax-transformations or macros which, frankly, most people should never use. For me, the best thing about Lisp is the regularity of the syntax. What I like least about almost all other programming languages is all the useless syntactic doodads and wingdings. The brackets, the indentation sensitive stuff, the unneeded complexity that languages insist on associating with what is and must be the denotation of a tree, in the end. The other great thing about the language is that you must use `let` or `lambda` to introduce variable bindings and their scope is, therefore, always perfectly clear. Despite these niceties, Lisp isn't going to make you into a super programmer. It won't really help you solve hard problems. It might help you quickly solve easy problems, but in the end, most of the job of a software engineer is grappling with conceptual problems with which Lisp is only sort of helpful. As long as I'm holding forth, I will say that I enjoy programming in Scheme _much_ more than I enjoy Common Lisp, which feels incredibly, uselessly, and old-fashionedly complex with all sorts of weird corners to stub your toes on.
- deleted 5y ago[deleted]
- reikonomusha 5y ago"Most people should never use [macros]" is not a very good take-away. This is silly and overly paternalistic, like most programmers are children who shouldn't enjoy an extraordinarily expressive programming tool because it's "dangerous to readability". I feel as though people imagine more macro horror stories than they've actually ever experienced. I've experienced just one horror story in an optional-use open-source numerical library. And so I just didn't use it because I couldn't figure out how to extend it for my needs. Many macros—just like programs as a whole—are bad and unhelpful. But this has little to do with macros, and more to do with programmer technique. It's not intrinsically difficult to write a useful macro, but it does presuppose that the programmer has a useful syntactic idea. The Lisp family of languages so so broad and loose. It's hard to say anything generally about them anymore. But if you narrow down to Common Lisp, there's still a treasure trove of unique features. Common Lisp and Clojure seem to be the only two lisps where you've achieved broad community agreement on tooling, ecosystem, and general library design. They're also two languages where you can get paid to write them. Can't say the same about Scheme. Lastly, as a personal anecdote, I don't think I've stubbed my toe on anything in Common Lisp. It's a very safe language with a lot of language features. I have stubbed my toe with CALL/CC though and memory leaks.
- dreamcompiler 5y agoNote that the examples in the "cdr" section are incorrect. (cdr '(x a)) ; does not return a, it returns (a) (cdr '((x a) y)) ; does not return y, it returns (y) (cdr '((x a) (y b))) ; does not return (y b), it returns ((y b))
- DonaldFisk 5y agoThe author might be new to Lisp, and I hope what I write doesn't discourage him. There are some other mistakes: ((ab . c) . d . nil) isn't a valid s-expression. Maybe it should be ((ab . c) d . nil) Also, (eq '(a b) '(a b)) ; (a b) is a list and cannot be evaluated by eq eq works fine on lists. It returns T iff its arguments are the same object (i.e. are at the same memory location, or are small enough integers or floats). If they're copies (as is the case in the above), it returns NIL. If this isn't what you expect, you should probably be using equal.
- joshtbradley 5y agoAuthor here, thank you for pointing this out! I was a LISP beginner when I wrote this, I'll certainly update this.
- lispm 5y agodon't count on (eq '(a b) '(a b)) being NIL. In Common Lisp it can be T. From what I read of Racket, it could be true, too.
- dreamcompiler 5y agoIf that were true I would consider it a very weird Common Lisp implementation. The main point is that you should never depend on it being true even though the two forms look the same. A couple more examples for the Common Lispers in the audience that highlight the difference between the reader and the evaluator: (setf foo (list #1=(list 3 4 5) #1#)) (eq (car foo) (cadr foo)) ; --> ?? What should we expect the second form to return? T or NIL? Answer: It might return true in some implementations (very weird implementations), but in general one should not expect it to do so. Why? (setf foo (list #1=(quote (3 4 5)) #1#)) (eq (car foo) (cadr foo)) ; --> ?? Now what should the second form return? Answer: It absolutely must return true. Why?
- theamk 5y agoA fun exercise when reading posts like those is to mentally compare to TCL. It is somewhat uglier - TCL's lists are multi-valued; and newlines are signficicant, introducing difference between "script" and "command". Still, the basic eval command looks remarkably similar in lisp vs TCL.
- nulbyte 5y ago> TCL's lists are multi-valued Can you elaborate? I am not sure what you mean.
- adenozine 5y agoArguments are evaluated in a different order to modern lisps. It's fexprs. It's weird in tcl because you might see weird macros that are built from the inside out, which is not how they're done with lisp. Like, with syntax-case, you're replacing terms in forms, but tcl does it with upvar and uplevel, so the relation of the form (whitespace matters) and you have to manage items carefully (scoping) It sucks. Tcl will break you down. Not original commenter, btw.
- theamk 5y agoI mean that Lisp's composite type, tuple, always has only two elements. Lists are just syntactic sugar over tuples. This means it is pretty simple to iterate via recursion, without special iteration-related functions -- see _evlist in the post for example. Compared to that, TCL's composite type is "list", which has an arbitrary number of elements, and recursive iteration is not as simple. Yes, one can use "lindex"/"lrange" to do LISP-style recursive iteration, but this is not idiomatic at all and has horrible performance. Instead, people use foreach/explicit numeric indices, and this needs more support and special iterating-related functions, see [0] for example. [0] https://wiki.tcl-lang.org/page/Map+in+functional+programming https://wiki.tcl-lang.org/page/Map+in+functional+programming
- bsder 5y ago> Still, the basic eval command looks remarkably similar in lisp vs TCL. The primary difference is whether arguments are evaluated before (Scheme/Lisp) or after (Tcl) being sent to the function/command. The deferred evaluation is what allows you to do things that you need macros for in other languages. (ie. you need deferred evaluation or macros to implement short-circuit operators, for example) However, early Lisps had FEXPRs which also deferred evaluation. The late John Shutt built and entire Lisp called "Kernel" around the idea: http://web.cs.wpi.edu/~jshutt/kernel.html http://web.cs.wpi.edu/~jshutt/kernel.html I strongly recommend a read through his PhD thesis: https://www.wpi.edu/Pubs/ETD/Available/etd-090110-124904/ https://www.wpi.edu/Pubs/ETD/Available/etd-090110-124904/ Unfortunately, his implementation isn't anywhere near as good as his conception. Other people have implemented it better. http://axisofeval.blogspot.com/search/label/kernel http://axisofeval.blogspot.com/search/label/kernel http://axisofeval.blogspot.com/2011/09/kernel-underground.html http://axisofeval.blogspot.com/2011/09/kernel-underground.ht... The Oh Unix shell grabs some of the core Kernel concepts and runs with them in a useful package: https://github.com/michaelmacinnis/oh https://github.com/michaelmacinnis/oh
- gaze 5y agoI have the same response to this as I do to every other lisp article. It’s cool, but how have you personally leveraged this advantage that everyone talks about? What big lisp project has the author contributed to, such that they have enough data to sing it’s praises?
- HeyLaughingBoy 5y agoI follow that up with knowledge of a large project that was started in Lisp (actually Scheme) that had to be converted to C# because the difficulty of finding experienced Scheme developers for the years of maintenance that would be expected was far more than the cost of converting to a language that's more "usable." Still remember all the meetings that generally always included someone complaining "what the $#&^%! were they thinking and why didn't their Management stop it before it got this far."
- closeparen 5y agoAs long as “hire experienced X engineers” is a non-negotiable requirement, you better choose a popular value of X. In parts of the community we do not so much think of the tools as part of the identity of the engineers. We’re looking for general intelligence/capability and train specific technologies on the job.
- seibelj 5y agoI know a startup that hired a Marxist-collective group of programmers. I was told this story years ago, and they were acquired, so I’ll just name the firm - “White Ops”. This story is so absurd that I’m naming the firm in hopes someone can verify the accuracy of this, although I trust the person that told me the tale. The programmers were based in Canada and only wrote in Haskell. The CTO of White Ops had apparently hired them previously as contractors at a prior company without issue. In hindsight, it turned out the purpose of Haskell was specifically because it was very difficult to hire anyone to replace them, and they wrote in a strange manner that left even experienced Haskell developers confused, especially without their customized IDE extensions. After a couple rounds of funding, the Marxists went on strike and demanded huge amounts of equity from White Ops to continue working. Ultimately the company wound up rewriting everything in a more popular language than acquiesce to their demands. I heard the Marxist group also had tons of drama because the leader made everyone live onsite in shared housing.
- codr7 5y agoPeople complain about the parens; truth is you have a lot of parens in most languages, just not so much concentrated at the outer edges but more interspersed. The only thing you would need to give up to drop them altogether is &key/opt/rest args.
- eternityforest 5y agoLISPs power is it's problem. Why would I want a powerful language? I want a language that has one and only one obvious way to do things. That doesn't require building my own language features or choosing an addon that might or might not be compatible with others. I don't have any use for the flexibility to customize a language because I want a language that doesn't need to be customized. If I was doing cutting edge AI i might feel differently, but I'm not. The stuff I do has only one place for creativity and that's the UI. The code should be boring and utterly forgettable. If someone remembers your code, it's probably because they had to spend time looking at it when they could have been writing unit tests or moving on to new features.
- rahimiali 5y agoEnlightenment doesn't come from actually using LISP, I've concluded, after years of feeling dumb about it. It comes from understanding how LISP is built. Once you understand how LISP is built, you'd never actually use it for a serious project. My key take aways from learning how LISP is built: 1) Code & data can be unified into the same thing. This isn't particularly deep if you know the concept of an AST. 2) You can bootstrap a language from a simplified version of the language. Repeat this a few times and you get a fancy language. This isn't particularly deep if you've built any compiler, or if you've built LaTeX. 3) You can build beautiful things if you disregard the grittiness of reality. LISP offers an abstraction of physical computers that does not at all resemble a real computer. Some people like this abstraction. Maybe because they don't like how computers actually work.
- patrec 5y ago> Why would I want a powerful language? You clearly don't, since your aim is to write boring and forgettable code. I don't think there is anything wrong with that -- you can write boring code to solve interesting and worthwhile problems, and overall the tendency is probably to err on the side of getting distracted by hip or shiny tech. But some people enjoy writing interesting code, and sometimes interesting code is needed to solve interesting problems and a powerful language can make certain types of interesting code much less painful to write. Auto-differentiation might be a good example.
- laluser 5y ago> Eric Raymond went so far as to say that understanding LISP is a “profound enlightenment experience.” Maybe this is true for language hobbyists or whatever, but every few years throughout my career, I went back to LISP or LISP-like languages and never found it super profound. Do I need to spend more time on a project? I just don't get the same excitement others seem to get.
- cracrecry 5y ago> Do I need to spend more time on a project? It depends on your interest. For me in particular Lisp was a "profound enlightenment experience" because: 1. I have been programming for a long time and had so many problems I could not(in practice) solve in any language but Lisp. 2. Lisp gives you two things no other language gives you: very basic Metaprograming(it can read itself) and the ability to design your own DSL(domain specific language). 3. It also gives you REPL(Read eval print loop) immediate feedback other languages tried to copy(but have not been able to replicate entirely). Having said that, Lisp design is also obsolete today because it was mainly designed in the 1970s. I hate it (specially parentheses and interface) and love it at the same time. >Do I need to spend more time on a project? You don't need to do anything, nobody needs to learn a new language for living. The fastest way to understand what Lisp is all about is to be near a very proficient Lisp programmer, because he will be able to run circles around you solving problems. That combination of someone proving to you what is possible at the masters level and natural human competition is probably much more powerful than anything else you could do on your own. We are humans after all, we see a great hunter hunt and only then we desire to be as good as he is and learn from him. We do it subconsciously and that is the reason elite tennis players sell razors so well, people copy naturally those who they admire without being conscious about it.
- p_l 5y agoSome of it is because a lot of features that used to be unique in Lisp (or few other "rare" languages) became way more available in other languages - partially thanks to Lisp&co popularising them first. Other stuff is that it tends to take some time working, and actually ending up using some of the more interesting bits, to see effect. Lots of people for example talk about macros when it comes to homoiconicity, but rarely (outside of old lisp wizards) do I see people going further to how Lisp makes it easy to build languages and compilers that are easy to debug and handle - I'm not just talking about the common idea trope of "write DSL for your program", because a) you're going to write a partial language specific to your program anyway, no matter the language, you might just obfuscate it calling them functions and types b) the easy manipulation of code and lack of parsing (and thus poof goes half the dragon book) means that writing compilers is simply... simple. And with CL's macroexpand and similar features in other lisps, it tends to be much easier to figure what is going wrong (and it's reasonably easy to add reporting of errors in compiled code down to specific form)
- Tomte 5y agoIs VScode with Alive a viable alternative to Emacs with SLIME nowadays? IntelliJ has nothing close to it, does it?
- vindarel 5y agoAlive has the most important features of SLIME (including debugger and restarts), so yes. It has less features and is more fragile still. Nope, saw nothing for IntelliJ. However if it highlights parens, one can code in there and `(load "myfile.lisp")` in any other REPL. It's a start.
- MrDresden 5y agoHaving only tried out Scheme and Common Lisp (I loved them both, what little I experienced) in my CS classes back in the day, I have always wondered how complex programs in these languages actually look like. I feel most examples just are the same list-manipulations / Fibonacci- / prime number calculation ad nauseam. Are there any active projects out there that Lisp family programmers would recommend as a good example of what the language can do and be used for (preferably with common elements such as networking, db connections etc)?