Ask HN: Learning Lisp, and I have some questions
- What are my package manager options? I can see quicklisp and qi. The quicklisp seems to install everything in a global folder. I am looking something closer to npm or bundler that stays local to my project. Qi seems like it. But I am still confused, what are my options here?
- What web frameworks are recommended. I don't need a full fledged framework, I need something micro, that just get's the job done. What are my options here and what's most recommended?
- For storage database I want to use something embedded and fast. SQLite is one option, what are my other options? Are there any "pure lisp" implementations of Key/Value stores?
- For hosting I know I can get it running on a VPS. Are there any other options I am not aware of out there?
I am total n00b so some questions might sound stupid to full time lispers, so bear with me :)
49 comments
[ 2.4 ms ] story [ 82.9 ms ] threadI think what you've said is reasonable, although it doesn't really address the poster's questions.
[0] https://leanpub.com/lovinglisp
Why do you need to host it somewhere else ? Just get it running on your development machine.
If you keep your data in memory, you may eventually want to store it somewhere so you can restart the service, reboot the machine, restore from older state, etc.
If you start managing the disk writing yourself and care about the edge cases (like ungraceful termination of your process or the os) you have quite a bit of work ahead of you. A service or library takes care of all of the right fsync calls on the right entities in the right orders for you.
In my view, the web application server’s primary function is to be a smart cache that responds to HTTP requests. The developer’s goal should be to prevent most requests from having to wait on a socket to return data.
The app developer has a tremendous advantage over the database simply because she knows what the data is. Personally I find that it makes a lot of sense to think of in-memory objects and their layout first, then treat the database as a persistence solution. This was not doable in the '90s because of memory constraints, but today the cheapest cloud VM instances have more memory than what you'd get on a high-end box back then.
You asked why this doesn't happen more often in practice -- I guess there is simply a lot of inertia involved. Many popular frameworks like Rails are designed around the broken stateless model and can't be reset easily. There are also large platform vendors who benefit from the low-performance solution: companies like Heroku are very happy to pretend that scaling means buying more crappy stateless server instances from them.
For most web applications it’s a terrible architecture if you need any kind of performance. The real advantage is that there is a huge amount of investment made in supporting this type of app servers, so you can build on something like Rails.
What's the point of building an app if this is what it's doing. Obviously this is not the case for the majority of web services. The minimum viable requirement for a robust website is that it can serve requests without blocking itself. You don't get this with a single threaded process.
The reactor model popularized by nodejs and nginx is the alternative exception to the concurrency model of traditional servers. At best the only type of memory you can use the app itself for is caching.
- Hutchentoot is very popular. Haven't used though.
- If you want common lisp only, IDK, but Clojure has Datomic. Though wrt databases, I'd rather care about quality, not implementation language, because it's mission critical software.
- NearlyFreeSpeech.net has SBCL and GNU Guile. But it's shared hosting. It should be easy to put an interpreter binary on a VPS kind-of service though. For Heroku there's a pack on github, though I don't have the link.
The only Lisp project that I could further is my emacs.d, because that's what I really use. I think that's key to learning something, having a real use for it. I wish you luck in your lisp adventure!
Qlot does allow more finer grained control, but I've never had a need for it.
Am I missing something?
That said, pretty sure you can find the specific answer if you need it.
1. Telling apart optional arguments to a function that weren't given from arguments that were given and were NIL. Typically giving a default value for the argument is sufficient to avoid the problem, but you can also add an extra parameter that tells whether the argument was given.
2. Finding an item that may be NIL. Functions such as GETHASH (which looks up a key in a hash table) usually allow you to specify a default value, and they will return a second value to indicate whether something was found. Notice that in CL additional return values can be ignored if you're not interested in them, so you only need to use MULTIPLE-VALUE-BIND when you actually need it. You could also wrap it in a trivial macro if you're using it a lot.If you want an empty list that isn't nil, you have to implement your own list type.
If you want a symbol called "NIL" that isn't self-evaluating and Boolean false, you have to use your own package.
In that context it's hard not to simply conclude that CL would be at a disadvantage.
Other conversions are possible of course. This scheme has the advantage of allowing you to naturally iterate over JSON arrays as lists in application code, but you have to take care of the fact that :false evaluates to T, by for example writing your own macros for "if".
This might read like a nightmare, but Lisp makes it really easy to customize everything about it self, which can be beautiful, if you're into that.
Perhaps because of the surrounding language?
Probably not, since C also has the same issue, and it's not very important there either, while at the same time being totally different as a language from Lisp.
What's so strange about it? That's how it has always been in C for example, Python didn't have a boolean type either for a good while, and lots of languages are like that.
It is actually the same in most dynamic programs also. A given expression, variable or object slot is understood to be a list, boolean flag or a symbol.
The fact that the domains of lists, Booleans and symbols happen to intersect is not relevant and doesn't really even come up. "Oh, this value a symbol too; nice, but we're not using it as one".
The empty list being false keeps a fair bit of unnecessary verbiage out of list manipulating code.
Variables and object slots being initialized to a default value of nil means that they serve as empty lists or false booleans, which is handy. A block of code which requires an initially stack can just be wrapped with (let (stack) ...). stack is ready to be pushed upon.
Really, when we consider everything, there is actually one item that is sometimes a bother: in a nested list structure, there is ambiguity between nil being just a symbol and a nested list. These two objects are equivalent: (a nil b) and (a () b).
If you're dealing with such data in which you need every possible word to map to a symbol that isn't an empty list, use a separate package, so that the "nil" token in the external data goes to mypackage:nil and not common-lisp:nil. (Treating such external data in a separate package is a good idea for other reasons, too).
[0] http://www.gigamonkeys.com/book/
[1] http://xach.livejournal.com/278047.html
- quicklisp is the default for package management. If you need to load a different version of a package you can use the local projects dir. I've never used Qi before, so I really can't say anything on it.
- For a framework I would recommend either Clack[1] (relatively small but featureful) or Ningle[2] (micro-framework).Both support multiple backends including Huntchentoot.
- There are object store databases and serializers like cl-store and cl-prevalence, but if you really want to take full advantage of Lisp I would recommend you use hash tables and reader macros. There's also plenty of mature (by lisp standards anyway) SQL APIs and ORMs like postmodern[3].
- For hosting I use AWS, haven't used anything else so can't say much on it.
[1] https://github.com/fukamachi/clack
[2] https://github.com/fukamachi/ningle
[3] https://github.com/marijnh/Postmodern
Leiningen is the standard build tool: install dependencies, run tests etc.
http-kit gives you the minimum needed for implementing a web server.
There are several key-value stores written in Clojure, but I would stick with SQLite (with the Korma library for nice composable syntax).
- for a URL shortener, Hunchentoot is already enough. Hunchentoot comes with an "easy-acceptor" scheme, which requires only (defparameter server (make-instance 'easy-acceptor :port 8080)) followed by (start server). But maybe you will need to define you own subclass of "acceptor" instead, I don't know.
- For storage, you can use hash-tables and serialize them with cl-conspack.
Note that conspack:decode-file returns a list of values.You can also interact with databases.
Watch these videos on a quick overview of Racket https://www.youtube.com/watch?v=vKjOTdVi99A&list=PLNm0vh7FGM...
You could program your pet project right afterwards. Also the documentation in Racket is better than any other community I have ever found. Clear, concise and uniform.
If I was to direct anyone into learning Racket I would say that 1) Realm of Racket is a great start for the language 2) How to Design Programs (Free online and a great resource)
Racket is just a great ecosystem that makes Deployment a piece of cake. I am a big polyglot but Racket has been my favorite find the past decade. Last time I got excited about a language was Python.
If you're intent on using Common Lisp, check out: https://github.com/fukamachi/clack
If you're willing to consider Clojure (widely used, actively developed, target platforms: JVM, browsers, CLR), there are _lots_ of options - I've had success using Ring/Compojure in small, web service projects. Check out Clojure Toolbox's "web frameworks" section: https://www.clojure-toolbox.com
Otherwise, if you're interested in Scheme (Guile, in this case), Artanis looks promising: http://web-artanis.com/
the power is in the lisp language & syntax extension, not reproducing 'npm install foo' using native calls and getting frustrated that the ecosystem is smaller
excuse snarky tone, simply typing quickly
1. Package manager is not required. 2. Framework is not required, that is simple application, you can have running as CGI under any server. 3. Storage database? Just use the LISP date stored in files, and you can even keep username/password there.
For ClojureScript, what package manager? npm. Also you may need Clojars and Maven for some Clojure(Script) packages. But you can use shadow-cljs to abstract the Clojars part. What framework? search in Node.js community, you can use it in ClojureScript. Which database? check out Node.js community. How to run on VPS? it's Node.js question.