10 ms·
Common Lisp: An Interactive Approach (1992)
- sillysaurusx 3y agoEven today it amazes me that python devs don’t live in the repl the same way that lispers do. The interactive approach is underrated. Especially in the era of test-first development, which I think is a fad long term. (That’s not to say no tests, just not tests first.)
- coliveira 3y agoPython doesn't work well for repl development. You cannot set the current module in Python as you can do in Lisp. So you're restricted to make changes to the current module. Also, debugging in the repl is not as powerful in Python.
- sillysaurusx 3y agoSure it does. Just paste the defs into the repl. You can also use `from importlib import reload` and then have an expression like reload(foo).bar() to constantly reload your foo library.
- kqr 3y agoBut this means you have to litter your application with support for it, doesn't it? In Common Lisp, I can stop at a breakpoint, paste in a new definition of any function in the application, and then resume and it will use the new definition everywhere rather than the one that existed when the breakpoint was triggered: https://two-wrongs.com/debugging-common-lisp-in-slime.html https://two-wrongs.com/debugging-common-lisp-in-slime.html
- vindarel 3y ago*and not only paste, but write, in the source file, the new definition, re-compile it (C-c C-c), and resume execution from a stackframe before this call. (a clarification for folks who would think we must paste in the REPL) That's useful not only for breakpoints but also for errors. We can fix an error without re-running everything from zero. https://www.youtube.com/watch?v=jBBS4FeY7XM https://www.youtube.com/watch?v=jBBS4FeY7XM
- oalae5niMiel7qu 3y agoReload only reloads one copy of the module. If there are other modules that imported the same module, your new definition will not be seen by them unless you find all the copies of foo in memory and reload them also. Since there's no reliable way to do that, you're more likely to just restart Python all the time.
- gilch 3y agoNot accurate as worded. Python caches module imports in `sys.modules`, so all imports get the same one. A `reload()` will reuse the same dict object that was being used as the module's namespace, so everything with a reference to the module object will see the same namespace and get the updates.
- mathisfun123 3y ago[flagged]
- dang 3y agoWhoa, please don't take HN threads into programming language flamewars, "slap fights", or attacks on other users. We're trying to avoid all that here. https://news.ycombinator.com/newsguidelines.html https://news.ycombinator.com/newsguidelines.html
- mathisfun123 3y agoI didn't say this should be a slap fight - I said the last one was. I'm always at a loss with how reading comprehension should lead people to conclude X here but instead they conclude Y. Like it literally says the previous one ie I don't know how I could've made it any clearer. Also you're perpetual quoting of the rule book under the guise of "here's our credo" doesn't accomplish anything because it doesn't clarify what rule was broken (and just serves to obscure the censure under "we don't like your kind around here"). At minimum you should cite exactly what rule was broken.
- dang 3y agoYou broke the rules against flamebait and calling names. If you'd just make your comments less aggressive, it would be much better.
- forward-slashed 3y agoCheck out lpy-mode
- gilch 3y agoWhat? Yes you can. I do it all the time. import code; code.interact(local=vars(foo)) where `foo` is the module object you want to set as current. This launches a subREPL in that module's namespace. (EOF kills the subREPL and returns to main.) Python has a debugger in the standard library that can also do post-mortem inspections.
- ggm 3y agoI'm trying to convince myself Jupyter isn't a form of living in the REPL expressed through tabbed state in a linear order, of python execution. I think it is, but I suspect it fails some boundary condition of significance. That said, when I did it, I didn't find it too hard to introspect on my code, in what it told me. I do think there is a meta going on around LISP repl and it's internal introspection which other REPL don't quite provide. You can come to almost the same place in output, but not at interaction with the run state of the 'machine' itself. (somebody else in the thread made the point its mostly there except handling exceptions in the stack)
- eschaton 3y agoJupyter Notebooks are absolutely a form of REPL, the type pioneered by MACSYMA, cloned by Mathematica, and significantly enhanced by Symbolics Dynamic Windows and Common Lisp Interface Manager (which is basically just DW but for any Common Lisp with CLOS).
- oalae5niMiel7qu 3y agoTry redefining something from a library that is used from a lot of different places. It's easy to change one copy of a definition in Python, but the only way to get all of them is to write your new definition to disk and restart Jupyter.
- wmeddie 3y agoI think you can argue that the pervasive use of notebooks is close enough for learning at least, but it's not as good for real development. The edit-and-continue features in Visual Studio for C# (and similar feature in Java) is the closest non-lisp thing we have these days. The languages aren't made for it like lisp are though, you have to do full restarts all the time. I still wish there was an environment more like Smalltalk for Python.
- fuzztester 3y ago>The edit-and-continue features in Visual Studio for C# (and similar feature in Java) is the closest non-lisp thing we have these days. Some years ago I was playing around with Franz Lisp, and noticed an interesting debugging feature in it. A few days later, I was using a then-new version of Visual Studio for writing either C (not C++) or VB, and noticed the same cool feature in it, which MS was calling Edit and Continue. IIRC, it was introduced in that VS version, but not sure, since I was not a regular Visual Studio user.
- pjmlp 3y agoOn Microsoft ecosystem, it was initially introduced in VB.
- fuzztester 3y agoInteresting.
- dmitry-vsl 3y agoShameless plug: I have always been fascinated by edit-and-continue and I build a JavaScript IDE centered around it. https://leporello.tech/ https://leporello.tech/
- rjblackman 3y agotest driven development has been around since the late 90s and was popularised in eXtreme Programming circles, are you sure it's a fad? I find it the most efficient way to write code and keep it running in the long term personally.
- oalae5niMiel7qu 3y agoYou simply can't in Python, not only due to unwind-first exception handling, but also because one module is represented by multiple objects in memory: one object for each other module that imports it. That makes it impossible to redefine anything (you'll always miss some of the copies of whatever you tried to redefine). Importing things from modules piecemeal makes it even harder to find them. The importlib.reload function only applies to one copy of a module. A comprehensive solution would be incredibly complicated and would still have limitations. In contrast, a Lisp package exists in exactly one place. No matter where you get it from, two references to the same package are always eq (having "is" equality in Python terms). Therefore, if you redefine something in a package, you redefine it for everything that uses the package. It also helps that imports in Lisp apply to the symbols, not the things they refer to. So importing something doesn't hide a copy of it anywhere. The most naive redefinition technique will always work, with no edge cases. The inability for class redefinition to affect already existing objects in Python is another severe limitation. Even if you could redefine anything reliably in Python, you'd still have this problem.
- psd1 3y agoI do a lot of python halted in the debugger, which is a close enough approximation.
- mark_l_watson 3y agoI do! I have been using Common Lisp since 1982, love it. But when I code in Python, Emacs with the old Python support gives you a really nice editing and REPL environment.
- cylinder714 3y agoIt's better, perhaps, to link to the parent page: https://cse.buffalo.edu/~shapiro/Commonlisp/ https://cse.buffalo.edu/~shapiro/Commonlisp/ Shapiro mentions "An even more up-to-date, faster introduction to Common Lisp" therein, if anyone's interested.
- nilamo 3y agoIt's even specifically called out that links directly to the pdf are not ok. > web links must point to this page rather than to a separate copy of the dvi, ps, or pdf file
- dang 3y agoThat is not really how the web works, of course. But I've changed the URL from https://cse.buffalo.edu/~shapiro/Commonlisp/commonLisp.pdf https://cse.buffalo.edu/~shapiro/Commonlisp/commonLisp.pdf now.
- deleted 3y ago[deleted]
- ilrwbwrkhv 3y agoSteel Bank Common Lisp is what I built my businesses on. Interactive software building is the work of magic. Nothing comes close. Once I retire and have some more free time I want to make videos and make open source contributions to make it more palatable and sexy for beginners. Folks are really missing out on a lot of joy and happiness by not programming in Common Lisp but I also understand why.
- anonzzzies 3y agoFor me David Botton [0] with his work including code, support and videos is doing very nice work in this direction. I use SBCL for everything but work because I cannot yet; we are getting there, but like you say, it’s such a nice experience working interactively building fast that it is magic and it’s painful returning to my daily work of Python and typescript/react. It feels like a waste of time/life, really. [0] https://github.com/rabbibotton/clog https://github.com/rabbibotton/clog
- android521 3y agofor someone new and mostly work in web/mobile dev, will you recommend SBCL or clojure/clojurescript?
- anonzzzies 3y agoFor most people clojure/clojurescript is the way to go as it's practical for building modern software. I'm working on something (but very slowly as I have a dayjob) to do this. I wish we had started in clojure(script), but that was not my call at the time (it is now). But in short; for now clojure(script) is the most practical way currently. Note: there is ABCL for running CL on the JVM, so for that you don't need clojure (I haven't tried but I have friends who use it and say it works well), however the JS issue (and I would need JS and interact with JS) isn't solved yet, as far as I know. I haven't looked recently, but threads like [0] are not that old and I cannot quickly see many things changed in that respect. So I would rather opt for what CLOG did and other Liveview type of systems, so it doesn't matter what happens in the frontend. WASM and (because now it's still needed) a robust JS implementation would be great. [0] https://news.ycombinator.com/item?id=21535165 https://news.ycombinator.com/item?id=21535165
- movingmovie 3y agoHow does Common Lisp compare with elixir. I'm trying to find a good functional language to learn.
- Zambyte 3y agoIf your goal is specifically to learn functional programming, I recommend you consider Lisp-1 dialects instead of Common Lisp, like Scheme or Clojure. While CL supports functional programming (it supports literally everything) functions exist in a separate namespace, and treating functions as data can be a little extra confusing. As for Elixir: it heavily leans on the actor model. Understanding this was the biggest hurdle for me, but once I got over that learning Elixir was a breeze (though I was already comfortable with FP by the time I picked up Elixir). If you want to go the Elixir route, I recommend trying to play around with an actor model system in a language you are familiar with first. I was familiar with Scala so I learned the actor model by playing with Akka. My #1 recommendation to you though is to go with Scheme and watch the SICP lectures. That will sneak functional programming into your brain without you even realizing it.
- waynesonfire 3y agoI had a similar question. I decided to learn Erlang / Elixir first. Starting with Elixir and thought that I should probably learn Erlang first since it's going to come up. I actually like Erlang a lot and use it as much as I can. There are use-cases where Elixir is more suitable, e.g. web development using the amazing Phoenix Framework. Anyway, I found myself doing REPL development using both Erlang and Elixir. Many of the benefits that I read about CL seem to exist within these languages as well. I hope to explore CL eventually, but I'm just having too much fun with Erlang / Elixir at the moment.
- vindarel 3y agoCL is the most interactive (by far). Its image-based development and its tooling (Emacs&Slime or other IDEs) offer more features. Elixir's tooling is more classic, focused on good tools on the terminal. CL has a pretty good type inference, which happens interactively too (you can compile a function with a shortcut and have instant compiler feedback). Elixir people say that in practice pattern matching alleviates from type issues. It seems to me CL will have a wider range of applications (good for number crunching, different implementations); it's possible to build self-contained binaries in CL. CL isn't entirely functional, nor pure FP, you can mutate things (and can not to with some care, or with libraries) and you can mix styles (with OOP etc).
- kazinator 3y agoThis book is how I got started in Lisp.
- vindarel 3y agoThose are good accompanying resources: - https://lispcookbook.github.io/cl-cookbook/ https://lispcookbook.github.io/cl-cookbook/ (recent and to the point, hope you like it) check out the editor section, there's more than Emacs these days: https://lispcookbook.github.io/cl-cookbook/editor-support.html https://lispcookbook.github.io/cl-cookbook/editor-support.ht... - https://github.com/CodyReichert/awesome-cl https://github.com/CodyReichert/awesome-cl for libraries - https://www.classcentral.com/report/best-lisp-courses/#anchor-1 https://www.classcentral.com/report/best-lisp-courses/#ancho... - a recent overview of the ecosystem: https://lisp-journey.gitlab.io/blog/these-years-in-common-lisp-2022-in-review/ https://lisp-journey.gitlab.io/blog/these-years-in-common-li... (shameless plug, on HN: https://news.ycombinator.com/item?id=34321090 https://news.ycombinator.com/item?id=34321090)
- beepbooptheory 3y ago+1 to the cookbook. Beyond reading the canonical books and referring to the hyperspec, it has been truly the most practical resource for learning more boots-on-the-ground things you will need to do in development. I wish some of the chapters weren't so focused on specific 3rd party libs, because some of it feels out of date now, but it is still by far more helpful than not.
- vindarel 3y agoOh, what chapters are you thinking about? We can fix them. Thanks for the feedback. (a cookbook contributor)
- beepbooptheory 3y agoOh hey! Sorry for the late reply. I am mainly thinking of testing, and if FiveAM is still the way to go, because there is a note at the beginning about Rove, which seems to be pretty well maintained these days. But looking at FiveAM again I see some recent commits. Also, in the concurrency chapter there is the section on lparallel, which seems like a very old unmaintained library. This all said, I think one thing that makes cl nice is that it doesn't feel out of the question to use a very old library for something you need. So none of this is actually a problem.
- nemesis17 3y agoThis was the first Common Lisp book I studied back in the 90s. Two of my Professors had done early work in AI and started a successful company that still runs on CL: https://www.siscog.pt/en-gb/ https://www.siscog.pt/en-gb/
- lisper 3y ago> The existence of packages (multiple name spaces for symbols) Sigh. It is depressing to see this kind of mistake in a book targeted towards beginners. There is already enough confusion around packages. Packages are not "multiple name spaces for symbols". A namespace is a set of bindings, and so a namespace for symbols would be a set of bindings for symbols, and that is the definition of an environment [1], not a package. A package maps strings onto symbols, so technically a package could be considered a set of bindings for strings, though no one actually thinks of them that way and they are never ever referred to that way. Packages are data structures that map strings onto symbols. That's all. One can only hope that this is an isolated mistake and not indicative of what goes on in the rest of the book. --- [1] http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_e.htm#environment http://www.lispworks.com/documentation/HyperSpec/Body/26_glo...
- beepbooptheory 3y agoCould you explain the significance of this blunder? Or like where this distinction would be important? I see lots of confusion between "packages" and ASDF systems, but none between packages and environments. It seems to me, I write a function in a package and whether I am in the package or using it, I refer to that function by the symbol it is given in the defun, even if really in the latter case its some sugar around a string implied by the original defun. Where will it matter to think about it the right way? When I need to shadow things maybe? Definitely take your authority on this in general, just genuinely curious.
- lisper 3y agoThat's a great question, and actually not so easy to answer. To understand it you have to put yourself in the mindset of a beginner, and here there are two possibilities: either you are a beginner, in which case putting yourself in a beginner mindset is trivial because you're already there, or you are not, in which case putting yourself in a beginner mindset is very, very hard because you have to actively forget (or ignore) things that you know, and that is not easy to do. I don't know which you are, but either way, I'm going to ask you to put yourself into a beginner mindset. So with your beginner mindset on, imagine reading this sentence for the first time: "The existence of packages (multiple name spaces for symbols) in Common Lisp is very important for allowing several people to cooperate in producing a large system." Now, as a beginner, you don't know what "package" or "name space" or "symbol" means, though you might have some preconceived notions about these words. But embedded in this sentence is the "fact" that packages are name spaces for symbols (whatever that might actually mean), and so you tuck this little factoid away in your mind so you can try to make sense of it later because the author has taken pains to point out that whatever it means, it's "very important". And then you read the rest of the book, where you find that the term "name space" is never mentioned again. At this point you might find yourself scratching your head a bit. So on the one hand the author takes pains to call out packages as "very important", and tells you what they are, but then never bothers to explain what the words that define them actually mean. So you, being intellectually curious, go to try to find out so you go out onto the Internet to try to find out what a "name space" is. A reasonable place to start might be the definition in the Common Lisp Hyperspec: > namespace n. 1. bindings whose denotations are restricted to a particular kind. ``The bindings of names to tags is the tag namespace.'' 2. any mapping whose domain is a set of names. ``A package defines a namespace.'' This seems promising, though it seems a bit odd that here a package defines a namespace, rather than a package is a namespace. Maybe "defines" and "is" are actually synonyms? But the bigger problem is that this definition is chock-full of new words which you as a beginner don't know the meaning of, most notably "binding". So you go to find out what that means, and your first step is to go back to the book, which turns out to be no help because despite the fact that it uses the word "binding" it never actually defines it, and also when the word is first introduced it is used as a verb, not a noun. So back to the Hyperspec: > binding n. an association between a name and that which the name denotes. ``A lexical binding is a lexical association between a name and its value.'' When the term binding is qualified by the name of a namespace, such as ``variable'' or ``function,'' it restricts the binding to the indicated namespace, as in: ``let establishes variable bindings.'' or ``let establishes bindings of variables.'' Whoa! That's a lot of new words, starting with "name", which is hyperlinked so it has a definition of its own: > name n., v.t. 1. n. an identifier by which an object, a binding, or an exit point is referred to by association using a binding. 2. v.t. to give a name to. 3. n. (of an object having a name component) the object which is that component. ``The string which is a symbol's name is returned by symbol-name.'' 4. n. (of a pathname) a. the name component, returned by pathname-name. b. the entire namestring, returned by namestring. 5. n. (of a character) a string that names the character and that has length greater than one. (All non-graphic characters are required to have names unless they have some implementation-defined attribute which is not null. Whether or not other characters have names is implementation-dependent.) Double whoa! What is an "identifier"? > identifier n. 1. a symbol used to identify or to distinguish names. 2. a string used the same way. OK, at least now this is a short definition, with only two new words, SYMBOL and STRING. So what is a symbol? > symbol n. an object of type symbol. Well, that's not very helpful. And at this point you might be forgiven if you decide that this whole Lisp thing is not really worth the bother and you really ought to go learn Rust instead because that seems to be what the cool kids are using anyway. The Right Way to explain this to a beginner IMHO is to start with strings because everyone has an intuition about what those are which is close enough: a STRING is a sequence of characters (which are a complicated topic in heir own right, but a naive view of what characters are is good enough to start with). A SYMBOL is a thing with a NAME, which is a string, and which cannot be changed. A symbol is created with a name, and it retains that same name forever. A PACKAGE is just a map, a function, from strings onto symbols such that the name of the symbol mapped from string S has the name S. This is significant because it insures that there is one and only one symbol with the name S in a given package at a given time. Packages are COLLECTIONS OF SYMBOLS WITH UNIQUE NAMES stored in a way that allows you to efficiently find the unique symbol with any given name in that collection. That's it (or at least close enough for a beginner). The reason this matters is that it allows different people to write code without stomping on each other. Alice can put her symbols in one package, and Bob can put his symbols in a different package, and so when Alice types "foo" into her code she can count on that referring to the One Symbol Named "foo" in Alice's package, and likewise when Bob types "foo" into his code he can count on that referring to the One Symbol Named "foo" in Bob's package. But these are nonetheless two different symbols (with the same name) and so Alice's code doesn't stomp on Bob's code. That's it. ~250 words with no unfamiliar terminology for a beginner to have to scratch their head over (assuming they already know what a "map" or a "function" is).
- narag 3y agoIf someone is considering learning CL effectively, take this piece of advice: use Emacs. You might think that it's an outdated piece of shit, maybe you hate RMS with a passion or whatever. But make yourself a favour and use it at least for the month that will take you to go through a manual like this or Practical Common Lisp or several others. Just install SBCL, QuickLisp, Emacs and SLIME (or Sly, that is a more featureful fork) and start hacking. I promise that you won't need more than ten hours to get hooked. Maybe you'll eventually like Emacs. If you're on Windows, watch this video right now: https://www.youtube.com/watch?v=VnWVu8VVDbI https://www.youtube.com/watch?v=VnWVu8VVDbI There's a moment at 12:52 when he invokes SLIME from inside Emacs. If you're confused how he does it, it's using Alt-x (or M-x in Emacs slang) and then writing "slime". Also at 2:40, to make a persistent environment string, there's now an easier way: in PowerShell write "setx HOME c:\Emacs" or whatever directory you choose. I use "C:\Lisp" and I put everything related under it: sbcl, quicklisp, emacs and my own projects. Other than that, even if the video is ten years old, everything works as advertised. That's true for most of the resources you will find around. Apparently nothing is showing much activity, but that impression is misleading. The core sbcl is getting relentless upgrades and the rest simply works. For web stuff, use Hunchentoot. Remember that quicklisp makes super-easy to download libraries. More interesting resources, apart what others have already mentioned: https://gigamonkeys.com/book/ https://gigamonkeys.com/book/ https://www.youtube.com/@CBaggers/videos https://www.youtube.com/@CBaggers/videos https://www.youtube.com/@GavinFreeborn/videos https://www.youtube.com/@GavinFreeborn/videos https://lispcookbook.github.io/cl-cookbook/web.html https://lispcookbook.github.io/cl-cookbook/web.html #clschool at libera.net. If some of the authors of those are reading this: a huge thank you!
- kaveh808 3y agoSome basic Common Lisp videos showing Emacs/Slime in action: https://www.youtube.com/playlist?list=PLTA6M4yZF0MzsMlNL0N67tIU12OLQ-R5K https://www.youtube.com/playlist?list=PLTA6M4yZF0MzsMlNL0N67...
- narag 3y agoI've just take a quick look but it looks great, thank you! It seems I'll need to use the Air to follow the series. As far as I can see it's ccl + aquamacs + slime... right? It comes at the right time because I'm starting with the CLOS part right now.