Practical Common Lisp (2005)
gigamonkeys.com
gigamonkeys.com
I wish that he would write some more books :).
At one point he mentioned writing a book to the effect of Statistics for Programmers, which sounds intriguing to me. AFAIK it hasn't happened yet, though.
Why intriguing? The most general family of distributions can only be expressed with a programming language, so there are certainly many connections between both fields.
Incidentally, that's one of my major complaints about Lisp these days. Lisp-Stat started dying in the early 2000s and completely faded away long ago. I read PCL when it was published a decade ago and I fondly remember how enthusiastic I became about Lisp.
I have used Clojure extensively, but the ecosystem for doing math and statistics is quite reduced. The same applies to CL and Scheme. I wish I could use one Lisp for most tasks.
> Why intriguing? The most general family of distributions can only be expressed with a programming language, so there are certainly many connections between both fields.
That seems to be an argument for why it is intriguing. Were you perhaps arguing that it wasn't surprising?
Maybe for the first chapter or two, certainly not most of the book. They're very fundamentally different languages.
I mean, my introduction to lisp was something to do with concat but it was so divorced from reality that I literally found an early book on C programming and semi-self taught myself it, then found a book called C Pointers and Dynamic Memory Management that literally changed my life.
I have a feeling if I'd read this book I'd have actually done something awesome by now. Frankly, this book might allow me to do something that I've been itching to do for months now.
I can't really express my appreciation enough... but I'll try right now: thank you! A million times over, thank you!
Edit: so Arc - is that like a Webserver based on lisp?
I've never been entirely certain what the relationship is between YCombinator and the Arc community, if any, but one experimental and partially black-boxed forum doesn't signal a mature language, just one adequate to a particular task.
What else have people done in Arc?
Anyway, I didn't intend to claim that Arc was a mature language.
But these days I pick a language with strong static types every time if I have the choice. I know you can use them with Lisp too to some extent but it's not the same as a language built from the ground up around types.
What topic are you into these days ? Or maybe you were planning for a sequel to PCL ? in both case really eager to see the resulting book(s).
I kind of suspect that if I write another book (as I hope to) that I'll continue along the trajectory from pure technical (PCL) to semi-technical (Coders) to something that might reach an even more general audience.
at the library, I also find it very good in how it presents programming, it's both hands on, concise and abstract at the same time. A refreshing view on the use of electronic machines.
https://github.com/jasom/lispstick-automate/releases/downloa...
https://github.com/jasom/lispstick-automate/releases/downloa...
It certainly shows some impressive Lisp techniques, and surely it will impress anyone who reads it about Lisp capabilities. The PCL made me feel awe about what Lisp can do. But not about what I could do with Lisp myself.
PCL doesn't really help the reader to really understand how all that code works to the point where the reader could write it without the writer's help.
I found this book: Lisp, An Interactive Approach https://www.cse.buffalo.edu/~shapiro/Commonlisp/ a better pedagogical tool to learn Lisp, and it guides the reader all the way, tests him, and makes him write all the needed code before going to the next chapter. It's not a showcase like the PCL book, but it imparts the reader with the ability to write a similar showcase himself.
The 'An Interactive Approach' book made me grok the power of Lisp in a way no other book could. It made me feel powerful and confident about what I could do with Lisp.
I think Paul Grahams ANSI Common Lisp is the best if you are learning Common Lisp and Lisp. The language reference in the end is the extremely handy compact reference for CL. http://www.paulgraham.com/acl.html
Common Lisp Recipes is better as a pure recipe book. http://weitz.de/cl-recipes/
I made a paper copy a while back, as is recommended by the authors. It's come in a lot of handy.
I disagree, and here's why:
Practical Common Lisp is the SINGLE Lisp reference I have ever found that talks about how to use real data structures instead of stupid cons pairs.
That's really, really huge. And it's probably why so many people actively dislike Lisp. And it's probably why Clojure achieved such popularity.
If you don't understand why cons is important, and the appropriate places to use it, then you really don't understand Lisp.
Lisp-the-mathematical-model, perhaps, but not Lisp-the-programming-language.
Conses are definitely a fundamental idea, and they're obviously how source code is written, and it's nice that they're around — but honestly for real work it's unlikely that most data will live in cons structures (unless of course the higher-level data structures actually are built from conses, which of course they could be).
I was going to suggest watching the video presentation "The Swine Before Perl", by Shriram Krishnamurthi, but alas I can't find a link to the video (which is sad, because it is a very entertaining and informative video). The slides are here: ( http://ll1.ai.mit.edu/shriram-talk.pdf ), but without the talk they may do you no good.
Hopefully someone will see this and add a link to the video ( it should be made available again, even after all of this time, it is still great -- I believe I saw it as recently as 2 years ago).
Then you haven't read many Lisp books, including Common Lisp Recipes and ANSI Common Lisp. There are so many of good ones.
To be fair, that's a 2016 book. Pretty awesome though, I have to say - I'd highly recommend it for anyone who knows a bit of Common Lisp (e.g. after PCL). It's basically the "Effective C++" of Lisp world.
Here's my point: People can build amazing programs with just Vectors or Hashes. People can build amazing programs without understanding recursion, evaluation, macros, or metalinguistic abstraction. And, in fact, before memory became cheap (roughly 1995) recursion was a negative, not a positive.
So, guess which things Lisp taught and which it didn't? Yeah, they got it precisely BACKWARDS and then wondered why Lisp wasn't more popular.
Go back, and look at Lisp books prior to the web--call it 1995-1996.
I 1987, I had a version of Touretzky's "Common LISP: A Gentle Introduction to Symbolic Computation". I do not remember any discussion of Hashes, Vectors, etc., but I see that even the 1990 version confines them to the next to the last chapter and the discussion qualifies as cursory, at best.
SICP doesn't even mention it. Nor does Little Schemer (nee Little Lisper).
"On Lisp" (1993) just drops hashes and vectors in your lap as it expects you to already know about them. "ANSI Common Lisp" by Graham doesn't appear until 1995.
CLtL and R4RS are references. You sure aren't going to learn Lisp/Scheme from those.
Sure, once Perl taught the universe how useful hash tables were, everybody started going "Hey, we have those too...", but prior to that is a big hole.
That's what Common Lisp provided back in 1984. Basic data structures like strings, characters, vectors, various numbers, I/O streams, records and hashes. It offer a lot of Lisp-stuff additionally, but it had everything to write plain programs.
> recursion was a negative, not a positive
That's why real-world Common Lisp usually avoided recursion early on and Common Lisp has lots of non-recursive iteration facilities. Scheme made some forms of recursion 'cheap' by introducing tail call optimisation (TCO) - which often is provided by Common Lisp implementations, too. But TCO was not standardised because it was difficult to integrate it with the rest of the language back then.
> I do not remember any discussion of Hashes, Vectors, etc.,
There were some books with more interesting examples, like the then popular LISP from Winston/Horn, where the 3rd edition from 1989 was fully moved to Common Lisp.
For key-value data structures Lisp traditionally used property lists, association lists and forms of search trees. Later some forms of object systems, which also map keys to values - like Frame systems. Larger Lisp systems used hash arrays (Interlisp) or hash tables (Common Lisp). Hash-tables were indeed not that often topic in the literature.
> CLtL and R4RS are references
The CLtL1 was quite good for learning Common Lisp. It's an nicely readable book and not the dense R4RS. CLtL2 made thinks difficult, because it was presenting the then defined ANSI CL (before it was actually finished) and all the deltas to the older CLtL1.
Highly recommended!
Quicklisp was first published in 2010 and is a library manager for Common Lisp.
On the other hand Quicklisp has serious issues:
+ Minimal if any documentation of internals.
+ A substantial chunk of the codebase can only be described as spaghetti code. To make matters even worse, most functions lack documentation strings. A sad state of affairs given the interactive and self-documenting nature of CL.
+ Is vulnerable to man-in-the-middle attacks since it verifies neither certificates nor checksums. This means that using Quicklisp can get you owned. Unacceptable these days.
+ Operates over a 'curated repository' model that Xach is managing. The repository has been found to be vulnerable to man-in-the-middle attacks in the past since packages were fetched over plain HTTP or git://. Even if that wasn't the case, it's yet another element in the chain of things to trust.
+ Few if any people besides Xach are working on quicklisp-client to mitigate these issues. Lack of documentation and spaghetti code is not helping to attract new talent.
+ Xach is employed by Clozure Associates. I understand that they've allotted him some time to work on Quicklisp while on the job, but it's still a side-project. Look at the number of open issues at Github. Many have been there for years.
For these reasons, I don't use Quicklisp myself. I also advocate against it to friends and colleagues who share my views on software distribution mechanisms.
If I had to guess however, I would say that the vast majority of Quicklisp users are not aware of the tradeoffs they are making. It's troubling that none of the security implications I mentioned are listed or even hinted at, in the Quicklisp site https://www.quicklisp.org/beta/release-notes.html or anywhere in the Quicklisp documentation.
One alternative is to improve Quicklisp. I don't want to be seen as blaming Xach here, but he's solely responsible for the lack of documentation. For CL docstrings especially, their absence is unfathomable for a core project that is positioned for wide usage. Every function, method and dynamic variable should have a docstring. You don't add these after the fact, you add them when you're writing the code.
If Xach improves the documentation situation, people will step in and start fixing issues.
That said, the patches I sat down to do would re-use native executables (md5, sha1) and wget/curl.
One can donate for Quicklisp work, even for specific features:
https://www.quicklisp.org/donations.html
Xach is working on a fundraiser effort to get it out of beta.
https://twitter.com/quicklisp/status/798316176082354176
> To make matters even worse, most functions lack documentation strings
It's not that there are no documentation strings. Example:
https://github.com/quicklisp/quicklisp-client/blob/master/qu...
> I also advocate against it to friends and colleagues who share my views on software distribution mechanisms.
It would be better to advocate to friends to help improve it.
At the end of the day it's the quality of documentation that matters. He did document some of the generic functions but in manner that is not very productive, as the doc strings are both minimal and don't let you get an idea of how the thing fits in the overall picture.
I would bet money even Xach would be confused going back to that codebase after a year of non-exposure.
I spent an afternoon trying to figure out how to add cryptographic checksum verification support. One could say the simplest of tasks. After a few hours of diving into that codebase, a picture of the whole was not emerging. Eventually I gave up in frustration. This is not ideal.
The core of Quicklisp is in dist.lisp. Understanding the protocol of the generic functions at the start of that file will help clarify Quicklisp as a whole. Almost everything else Quicklisp does is in support of that protocol.
It may be not obvious to those who may only have had a limited experience with it, Common Lisp, in itself, is an extremely expressive and powerful programming language. Also, there are compilers, such as SBCL, that generate a very efficient machine code; others, such as ECL ("embeddable Common Lisp"), make it very easy to combine lisp code with code written in C, thereby providing the ability to seamlessly integrate high-level and easy-to-use constructs with low-level, performance-critical pieces of code.
On the other hand, quoting Einstein's quote found in the famous book by Sussman and Wisdom who use Scheme to teach Classical Mechanics, "I adhered scrupulously to the precept of that brilliant theoretical physicist L. Boltzmann, according to whom matters of elegance ought be left to the tailor and to the cobbler.”
Somehow I think the analogy falls apart on close consideration. ;)
In this case, though, I think it still works. It says nothing of the work they do, but more to the goal of their work. Tailors/coblers (fashion, in general) are tasked with making elegant attire. It is true that some are tasked with making practical attire.
Physicists, however, are never tasked with making elegant physics. It is rewarded. But it is not directly their task.
> An analogy is like a finger pointing at the moon, pay too much attention to the finger and you miss out on all the heavenly glory.
The other thing about Lisps is that if a programmer doesn't like the order of arguments or the function names or even the parenthesis, the language lets them change whatever it is they don't like and the changed features still have first class status. That's also one of the criticisms of Lisps.
And I do understand why CL is the way it is. That doesn't mean it's perfect (neither is Scheme: I just happen to prefer it).
Historically, Scheme somewhat dodged avoided issues like argument order by excluding functionality from the language spec. My experience is that once Scheme gets expanded out and becomes Racket, the many hands show up as inconsistencies among similar functions much like Common Lisp.
Clojure, to me, seems to have the right idea: procedures that abstract operations from data types...for example there is not one mapping procedure for lists and another mapping procedure for arrays. Racket seems to be headed in that direction.
In Common Lisp, MAP works just as well on either.
None of which is to say that Clojure isn't standing on the shoulders of giants.
er (or explicit rename) macros are the simplest system: they're like CL macros, with a few minor differences. Also, because Scheme is a lisp-1 with a mutable global environment, you have to rename absolutely everything. Even lambda. Yes, really.
Because of this, CHICKEN (the only scheme that uses er macros) also has ir macros, which are like er macros, except that everything is implicitly renamed unless you say otherwise. However, expanding an ir macro is O(n) under the hood, which sucks. This is probably the worst part of CHICKEN, but it works well enough.
sc (syntactic closure) macros are similar to ir macros in nature, although the syntax and abstraction is different. It's a pretty nice system, currently used in Chibi and MIT scheme, and (while it's really too early to tell) seem to be the macro system most likely to make its way into R7RS-large.
Finally, there's syntax-case. It's used by racket (I think: racket's syntax-case has apparently been heavily extended) and guile, and is the R6RS macro system.
Personally, I don't like syntax-case. IMHO, it's overly complex, it throws away the standard macro abstraction for little benefit, and is generally a pain to use. But it's not objectively badly designed, and some people seem to like it (conveniently, this description, with some minimal modification, applies quite well to R6RS itself). You might be a person that likes it. I don't know. All I know is that I am not one of those people.
Obligatory link: A Short Ballad Dedicated to the Growth of Programs. http://people.cs.uchicago.edu/~wiseman/humor/large-programs....
But yes, it's one of Scheme's few failings. And it's one of the things that makes me consider switching to CL.
As much fighting as there is between them, they're not that dissimilar...
"Lisp" means so little when you're writing real code.
Each implementation has its own quirks and even venerable books fall when confronted with real world code at learning.
For example: I was reading the SICP and using racket that looks like an interesting runtime nowadays. Turns out that a while a go the dev team made cons immutable and that's okay I guess but it broke (at least for me) the experience of reading SICP because I now have to pause and learn this quirk of this specific lisp implementation.
And don't even get me started on common lisp. There are at least 5 or 6 major common lisp runtimes, each of them incompatible somehow (try and read some of the StumpWM "makefiles" and you'll have a taste of what I'm talking about).
Also, common things (threads, for example) are still not provided in a uniform way across all of the implementations, and are often more or less quick hacks.
Scheme? Cool! Srfi! What part of scheme does your scheme actually implements? Would you use a C compiler without structures? And write code so that it can be compiled with another C compiler that has structures but doesn't have foot loops (only while loops are provided).
Lisps are awesome languages, but for me, no wonder they remain niche languages.
And before you downvote, please keep in mind that I am now booing Lisp, I would just love it to be more "sane" minded and less schizophrenic as a language/runtime, and more real-world-usable.
Edit: Not to mention, C only got threads in the most recent revision of the standard, and I can't say anything about their implementation because I've yet to encounter a project that uses C11.
https://github.com/sionescu/bordeaux-threads
and
I guess this pretty much sums up the state of many common lisp libraries.
Also, if it is so portable and so useful, why hasn't it made part of the language and of the various implementations?
Why there are no updates to the standard?
https://common-lisp.net/project/bordeaux-threads/
> Also, if it is so portable and so useful, why hasn't it made part of the language and of the various implementations?
You make it a part of the language by loading it in.
CL-USER 23 > (ql:quickload "bordeaux-threads")
To load "bordeaux-threads":
Load 1 ASDF system:
bordeaux-threads
; Loading "bordeaux-threads"
[package bordeaux-threads]...
("bordeaux-threads")
> Why there are no updates to the standard?Because it is too expensive (it's an ANSI Standard, which makes things difficult), there are no sponsors for it and not enough are interested to do the work.
The language evolves in libraries, portable substrates and implementations since some time.
Note that the language has a lot of flexibility for change built in: reader macros for the s-expression syntax, macros for the Lisp syntax, meta-object protocol for the object-system, packages enable new Lisp dialects, ...
Is it though? I think the biggest problem is employment prospects -- it's just not used enough in industry. I have used a lisp professionally, and I am of the opinion that that opportunity was a one-time thing career-wise for me. these days, I can't justify spending time on anything but Java or C++ in terms of my career trajectory. would like to hear others' thoughts though.
Common Lisp is a different story though, the standard is comprehensive and it's easy to go from one implementation to another, often requiring no effort.
In most cases where there's an incompatibility among two Lisp environments, you can just write a macro or two to sort it out, whereas with C, if you don't have a for loop, you either patch the compiler or use the while loop.
I'm pretty sure that you're supposed to choose the correct language in Dr. Racket if you want mutable cons semantics (such that you're using R5RS and not Racket).
Or get #lang sicp from pkgs.racket-lang.org.
https://github.com/rongarret/BWFP
Currently very low on my priority list but it would not take a lot of encouragement for me to pick it back up again.
Reading it was eye-opening. I had no idea up until that point that Lisp is a real, industrial-grade language (as opposed to a very interesting didactic tool).
Even if you don't have an intention of programming in Lisp, you should read PCL for an idea of how much better the language you're programming in could be. Hopefully, it'll inspire you to write some Lisp, but even if it doesn't you'll be a better programmer for it. You'll be able to understand why static languages like Java have such arcane ecosystems; you'll be able to see how very little new there is under the sun.
I wish there were an update to this book. I seriously looked into giving up on JS and using Parenscript and Wookie or Hunchentoont but it seemed like I'd be taking on a lot of yak hair. Does anyone here use any lisp for Web Development? What's the modern lisp (CL or otherwise) stack?
I've been writing Clojure for about a month now, and I love it.
My background is mostly in Python, and I picked up Ruby about a month before Clojure. My rampup in Ruby was really about a week, given that much of it is so similar to Python - it was mostly about learning conventions and what the community considers to be "idiomatic Ruby".
Clojure was much more difficult to learn, and much more fulfilling/enjoyable. It's definitely changed the way I think about my code in all languages and that's a good thing. One thing I will say though is that the majority of the time I've spent struggling with Clojure has actually been struggling with Java.
For example, I wrote a collection of forms that decrypt and validate an auth token sent by a third-party legacy application. This required using java.crypto, which was a nightmare. I was porting code from Ruby, which was using OpenSSL. At one point I had references for Clojure, Java, Ruby, OpenSSL, and C all open at once, trying to figure out what was going on. In the end that particular problem was because Ruby's OpenSSL wrapper magically use an IV of eight null bytes if you don't supply one while java.crypto didn't use one at all - but it was one of the more difficult issues I've had to debug in recent memory.
I guess what I'm trying to say is that I would absolutely recommend Clojure as a first Lisp to learn, but I would also suggest that the person doing so either already have some experience in Java or have a way to reach out to someone who does.
I'm planning on picking up CL at some point soon as well, but from what I've experienced and gleaned from the experience of others Clojure is probably the better choice is your area of interest is mostly the web, because of the dev community and access to Java libraries.
I remember tinkering with Scheme when I was much less experienced, and getting hung up on the constant recursion and singly-linked nature of the iterables. I'll get back to that, but I strongly suspect that Clojure will remain more practical for the type of work I do (back-end web, mostly).
> If you wrap your head around macros in Clojure that will mostly carry over to CL
I've not tackled writing them yet, but I've read a ton of the language internals and other people's code and I'm getting to the point where I can anticipate where they've used macros and why. I've also begun reading - slowly - Let Over Lambda, which has kinda blown my mind. My colleagues with more Clojure experience strongly advise me to treat macros as black magic that should rarely be used, but my opinion is slowly but surely going the other way. Macros seem like most of the point of using a homoiconic langauge, and to reserve them for edge cases seems unduly conservative. We'll see if that opinion changes as I learn more and begin to use them in my own work.
> If you're interested in Lisp, learning Clojure first is sort of like learning Spanish because you're interested in French.
I'm honestly not sure what I'm interested in learning right now. I feel like I fully grok Python. Though of course there are things I can't sit down right now and write without looking at a reference, I know what tools to use when and why they're appropriate. Having not acquired a compsci degree, I'm basically looking into the more esoteric languages and design patterns at this point, trying to find concepts that expand my abilities and knowledge. FP was one of those things, the concept of homoiconicity was one, and macros seem to be another.
Haskell looks interesting to me as well, but I'm cautious of the passion of their community. My impression is that they believe they are the "one true functional language", and with things like Lisp having been around for much longer in that role that seems a little too "flavor of the month" for me.
No one writes code like that in Common Lisp. Both Scheme and CL have more than singly-linked lists, as well.
> I've also begun reading - slowly - Let Over Lambda, which has kinda blown my mind.
I haven't read that one but I've heard good things. I can personally vouch that Paul Graham's On Lisp is excellent, as a book on macros, Lisp, or just in general.
> My colleagues with more Clojure experience strongly advise me to treat macros as black magic that should rarely be used, but my opinion is slowly but surely going the other way. Macros seem like most of the point of using a homoiconic langauge, and to reserve them for edge cases seems unduly conservative. We'll see if that opinion changes as I learn more and begin to use them in my own work.
If a function will do, use a function, but macros serve a different purpose. Over time you build up an intuition for which one you need in which situations.
> I'm basically looking into the more esoteric languages and design patterns at this point, trying to find concepts that expand my abilities and knowledge.
That's a very good strategy :)
It looks like I'm a bit further on this particular road, so let me give some suggestions:
1. Take a look at array-based programming languages. I used J (google "J lang" or got to jsoftware.com). It's incredible how you can have a single, two characters long symbol encode concepts such as recursiveness and have that symbol be easily composable with any other function in the language. Learning J or APL or K will change the way you think about tables, probably influencing both your NumPy code and SQL code.
2. Try some concatenative languages. Forth and Factor are fine examples in this category. Forth is a very low-level, completely untyped language with built-in interactive mode; it's mostly built in itself and bootstraped with a bit of assembler. Factor is a modern language with rich data types and batteries-included style standard library. Both use stack for passing arguments and both are interactive, but that's all they have in common, so learning both is not a waste of time.
3. Learn a pure object-oriented language, like Smalltalk (I think Pharo is the most popular implementation right now). It's not at all Java-like experience, having only objects at your disposal is not that bad if you can make the objects behave just the way you want them to: even things like the stack are objects and can be inspected and manipulated like all other objects. There's also Io to look out for: it's not as impressive as a full Smalltalk environment, but it's even simpler semantically and allows easy syntactic extensions.
4. Learn a logic programming language. It's great for quickly solving silly puzzles. It's not bad for dealing with textual data. It honestly sucks for everything else, and everything else breaks the pure-logic semantics, so it's not that practical. It's a bit better when used as an embedded DSL from some other language.
5. Learn (delimited) continuations as implemented in Racket. There are other languages which support some form of continuations, and there are even some frameworks which use continuations in these languages (see Nagare web framework for Python or Seaside for Smalltalk). Continuations will give you tools for understanding generators, coroutines, restarts and many other language constructs.
While there are many excellent server-side lisps frameworks (I don't know CL super well, but I know they've got them, and here in schemeland, we've got Awful, Artanis, and whatever Racket uses (even though Racket isn't really a scheme), depending on your implementation. As a Chicken fan, I like Awful). However, the clientside situation isn't so great. CL doesn't have a clientside version, AFAICT (although with WASM, this may come). Chibi's got an emscripten compiled version, but now you're running one VM on another. Chicken has Spock, which is an almost-R5RS that compiles to JS, but the cost is high: it reportedly stresses your browser in unusual ways, has a runtime you have to add to your page, and it doesn't have eval (hence "mostly" R5RS).
Maybe now that WASM's here, things will get better.
At the risk of making it known that the joke went over my head, can you link me to the Awful?
The only "chicken" programming language of which I'm aware is this one: http://torso.me/chicken
(Chicken Scheme is the Chicken)
It's a scheme to C compiler (with an interpreter, of course) that implements Cheney-on-the-MTA compilation (so continuations are almost free), a very nice macro system (although with some unfortunate performance implications), and has a relatively large library repository (for a scheme), as well as an stdlib that emphasizes practicality over purity (it even includes a regex library in the default install) while still keeping the simplicity that makes me love Scheme: I can keep the whole language in my head. Plus, if it doesn't have the library you need, writing C bindings is a piece of cake (because it compiles to C, anyways).
Awful is the name of its web framework.
I got ABCL to load on it, but it took 8 hours on chrome on my machine :(
[edit]
Type "kawa" at the prompt once it loads to lauch kawa scheme.
I do.
> What's the modern lisp (CL or otherwise) stack?
There is no fixed stack, though people want to make you believe there is.
I use cl-who for html generation, my own lib for css generation (basically sass with lisp syntax), a bastard of cl-json for json generation and a heavily patched hunchentoot as a web server and in very rare cases parenscript - but only to generate js class definitions from cl classes since transpilation of business logic usually places too many constraints on what you can implement how on the lisp side. For database access I mostly use cl-postgres but fall back to cl-sql if the client insists on another DB than pg.
> There is no fixed stack, though people want to make you believe there is.
My stack:
I use parenscript[5] fairly heavily (to the point where I'm now a contributor). Note that parenscript is mostly javascript semantics with lisp syntax, but macros for it are written in common-lisp, which makes a lot of the javascript annoyances go away.
Like jlg23, I use cl-who for html generation.
I spent a while experimenting with css generation, but now just use something prepackaged (currently Pure[1]). If I had need for a custom look, I would pay someone who knows graphic design to generate a layout, and I'd code to that.
I've rotated between several JSON libraries to the point that I couldn't say which one I used for my last project; for JSON I'm very opinionated on the proper mapping from JS types to lisp, and none of the libraries do the Right Thing out of the box, so I wrap them with something that will.
As users expect something less like "fill out a form and hit submit" and more like "Instantly responsive web application that saves my work as I go" I started experimenting with using parenscript with various JS application libraries. I found React to be okay[2], but much prefer the simplicity of Mithril[3].
For webserver, I use clack[4] which is in roughly the same space as WSGI is for python or Ring is for clojure. It is sadly severely lacking in documentation (at least in English). A clack tutorial is on my "todo" list.
I happen to run clack behind mongrel2, but that's because it's the server I'm most familiar with; it has backends for FastCGI and several native lisp web servers, and adding new backends is very easy (the mongrel2 backend is under 200 lines of code).
For a database I use postmodern[6] (a library for pgsql) and I use cl-redis[7] for quick & dirty projects, as a key/value store tends to make for more rapid prototyping.
2: https://github.com/jasom/parenscriptx
3: https://github.com/jasom/parenscriptm
4: https://github.com/fukamachi/clack
5: https://common-lisp.net/project/parenscript/
The code behind the site https://news.ycombinator.com is written in a Lisp: http://arclanguage.org
Saw this recently:
http://www.adamtornhill.com/articles/lispweb.htm
It might be useful, even though is from 2008, if it focuses on fundamentals.
Saved it for later reading, since I'm not learning Lisp currently, though had read a part of the Practical Common Lisp book earlier. (Had liked what I read of it.)
I presume you can do the same with Common Lisp tools. Does anyone else here do that?
Everything else currently feels deeply lacking.
Server side CL is a lot better covered.
https://engineers.sg/video/web-development-in-emacs-common-l...
CL-USER> (remove-if-not
#'(lambda (cd) (equal (getf cd :artist) "Dixie Chicks")) *db*)
((:TITLE "Home" :ARTIST "Dixie Chicks" :RATING 9 :RIPPED T)
(:TITLE "Fly" :ARTIST "Dixie Chicks" :RATING 8 :RIPPED T))
It seems to be missing a single quote... shouldn't it be: CL-USER> (remove-if-not
#'(lambda (cd) (equal (getf cd :artist) "Dixie Chicks"))' *db*)
((:TITLE "Home" :ARTIST "Dixie Chicks" :RATING 9 :RIPPED T)
(:TITLE "Fly" :ARTIST "Dixie Chicks" :RATING 8 :RIPPED T))
If this is a typo, it merely shows how incredibly well written this is, because I have literally never read lisp code in any seriousness in my life!Generally, preceding single quotes in Common Lisp e.g. 'FORM are syntactic sugar for (QUOTE FORM) which has the meaning of reading in the form without evaluating it. You'll see lots of single quotes used for that purpose as well.
CL-USER> (remove-if-not #'evenp '(1 2 3 4 5 6 7 8 9 10))
(2 4 6 8 10)
The author explained what #'evenp did (FUNCTION '(1 2 3 4 5 6 7 8 9 10)) but not that '(1 2 3 4 5 6 7 8 9 10) is just (1 2 3 4 5 6 7 8 9 10).In other words, the above evaluates to:
(FUNCTION evenp (1 2 3 4 5 6 7 8 9 10))
Or didn't explain it unless, of course, I missed a bit :-) (defun how-is-it-read? (string)
(write-to-string (read-from-string string)
:pretty nil))
==> HOW-IS-IT-READ?
(how-is-it-read? "#'foo")
==> "(FUNCTION FOO)"
(how-is-it-read? "(remove-if-not #'evenp '(1 2 3 4 5 6 7 8 9 10))")
==> "(REMOVE-IF-NOT (FUNCTION EVENP) (QUOTE (1 2 3 4 5 6 7 8 9 10)))"
You can see that this does not match your expectation. Are you actually trying to type that code and evaluate it at a Lisp listener? If not, you should.Now, FUNCTION is a special operator that in this case returns the function named EVENP.
QUOTE is a special operator that just returns the object it is passed.
So REMOVE-IF-NOT will get called with two arguments: the function named EVENP, and a list of integers from 1 to 10.
I remember that when I was last trying to explore it, that was the single biggest hurdle - all the recommended freely available "industrial strength" implementations (SBCL, CMUCL) were either unavailable on Windows outright, or considered experimental and highly unstable there. The stuff that was available was either proprietary (and costly), or its performance was not deemed sufficient for production use (e.g. CLisp).
But that was several years ago. Did anything change?
It is a lot better, I don't think SBCL gets the "kitty of doom" start up message anymore. I'd love it if you'd try and let us know :-) (or you could just ask on #lisp). I know for a fact that Clozure CL works well on Windows.
CCL has no interpreter, so any code you write gets compiled to native code. People worry too much about performance too prematurely in my opinion.
I hate windows in general and try to avoid using it and targeting it whenever I can, but for the past year I did use windows+ccl+emacs to successfully get work done, which I was able to easily transition back over to macos+ccl+emacs just recently.
I would say that at the very least, the hurdles you ran into in the past are gone. Binaries for sbcl on windows are supplied, and I'm pretty sure that threading is enabled in recent builds so no need to recompile yourself (I remember wasting so much time on this a few years ago and moved to ccl).
I recently ran into a workflow that ccl easily accommodated that sbcl didn't, which was specifically such that when you ran out of heap, ccl automatically allocated more, whereas with sbcl it seems to be fixed upon startup and requires more than a command line flag to fix (I couldn't figure it out in the hour or so I spent working on it)
Thank you for writing this book and sharing it with the world!
Thanks!
Practical Common Lisp + Land of Lisp + Common Lisp recipes + the Lisp Hyperspec = Profit!
Additional readings: Successful Lisp (Lamkins - very underrated), Paul Graham's books, and Hoyte's Let Over Lambda (advanced).
I wonder if it can take any credit for the resurgence of lisps! (especially Clojure)
It certainly was an influence on the student writen 'Realm of Racket'.
The cool thing about the challenges is that they are language agnostic so you can try whatever you're interested in (CL, Scheme, Racket, Clojure, …). A bit like Project Euler (https://projecteuler.net) but more fun.
AoC is great. I've been doing it in Scheme. Except today's challenge, which I did in AWK, because it was perfectly suited for the task (although I could have also used the AWK scheme macro). Plus, in Scheme, you don't wind up with code like this
{if(($1+$2>$3)&&($1+$3>$2)&&($2+$3>$1)) count++;} END {print count}
Aren't one-liners fun?It's more abstract with programming, but programming a website gives pretty good and immediate feedback. Plus you can show it off.
So even though I'm not a web dev, I still think learning to build a dynamic website or web tool or service is a really great way to get introduced to a language. It will give you a rooting that you start branching out from.
Clojure in particular is pretty good at the web dev thing. I'd just stick to server stuff to start with personally.
I would recommend SBCL unless you want to do GUI stuff.
I much preferred Land of Lisp by Barsky for the basics and Edi Wietz' Common Lisp recipes for specific use cases.