Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Between two Lisps (ane.github.io)
142 points by galfarragem on Dec 5, 2020 | hide | past | favorite | 100 comments


If CL had only two namespaces, it would be odd and random, but not unique. It's like writing `./foo` vs `foo` in shell. Common Lisp is naturally more like operating system than programming language anyway.

But once you realize that CL has more than two namespaces (I think it has at least nine in the language itself, unlimited in user programs) it's easier to understand how it can be more than historical accident. People are used to thinking words in context.

I do mostly numerical programming today. Common Lisp would have been my preference and IMHO much better than Python I have no time to rewrite numpy or R libraries in CL.


Julia (runner up R) feel like the lispyest non-lisps to do serious numerical work in. Julia’s at the point where it has some best-in-class libraries as well as some frustrating blind spots.

With Julia I can almost pretend I’m using a straight-up lisp. The multiple dispatch in Julia is quite nice and is sort of “the big idea” that Julia uses to be so magical.


Similar to Dylan's experience, sadly Apple canned it and it never got that much uptake afterwards.

However there is OpenDylan for anyone that would like a go at it, including the old book describing the language.


I’ve heard people talk about how similar Dylan and Julia are for a long time, but have never used Dylan myself. Are there any things that are standouts for Dylan as compared to Julia that are worth checking out?

I feel like Julia is pretty great, and has a good amount of inertia behind it in the domains that I frequent, but I’m curious about (Open)Dylan from the perspective of someone who’s used both.


I feel like Dylan is much more dynamic and OO than Julia. I don’t think there’s a way to have parameterised types (like generics in Java or C#) and a lot of the arguments for Julia’s type system are about being able to generate efficient code by being informed by the types. The parameterising complicates the subtyping relationships needed to specify how multiple dispatch works.


Sorry, maybe I'm misreading your comment, but are you saying that julia doesn't have parameterized types? If so, that's untrue, but maybe you're saying Dylan doesn't have parameterized types? It's a little unclear in the text.

> The parameterising complicates the subtyping relationships needed to specify how multiple dispatch works.

I don't think it adds all that much complication actually, and it adds a ton of extra expressive power. For instance, our arrays are parameterized by their element type and their dimensionality, so

    Array{Int, 1}
is a 1D (vector) array of Ints whereas

    Array{Complex{Float64}, 2}
is a 2D (matrix) of Complex Float64s. This is really important for making the most of multiple dispatch imo because I can write methods which take advantage of as much type information as possible. This isn't just helpful for performance, but also helpful for just expressing your algorithm in a clear and general way.


When I last wrote Julia I think it was unclear to me how subtyping worked with type parameters, or writing type specifiers for methods was complicated by them. I think all type constructors are invariant, so you couldn’t have T{X} < T{Y} unless X = Y (but I think you can have a rule like S{X} < T{X}). This makes sense in some cases as covariance or contravariance don’t work for arrays (suppose I want an Animal array but you give me a Dog array, then when I read elements I get Animals as expected but if I were to try to write a Cat there, it would be bad. Java has this rule and will throw a runtime extension in the case described), but it can work for immutable types, though Julia can’t enforce that all subtypes are immutable and type parameters needn’t be types anyway.


Dylan doesn't have parameterized types.


You can get around it with multi-methods.


For many blindspots you can use PyCall (https://github.com/JuliaPy/PyCall.jl).


The standard Common Lisp namespaces I can count off the top of my head are variables/symbol macros, functions/macros, compiler macros, types/classes/condition types, class slots, TAGBODY tags, BLOCK names, THROW tags, restarts, documentation types. Users can easily define new ones.


I’m not sure I’d count compiler macros as a separate namespace to functions or macros. It feels like they’re the same to me. I think I also wouldn’t count throw tags as a namespace as they can be objects rather than symbols (but then again lists like (setf foo) are valid function names).

I think method combinations and packages are other namespaces.


Yes - thank you for the additional namespaces and about the THROW tag correction.

As for compiler macros, they do have their separate namespace, accessible via the `compiler-macro-function` function. They can be invoked instead of functions, but they exist completely on their own.


And types and classes are subtly different namespaces BTW. Try specializing a method on KEYWORD. In pure ANSI implementations you can't because KEYWORD is a type but not a class, and method specializers have to be classes.


Yes, but defining a class always defines a matching type - hence they share a namespace in a way.


> I have no time to rewrite numpy or R libraries in CL

It's been done. I have no experience with it but a numpy clone in CL exists.

https://github.com/numcl/numcl


No it hasn't.

Ignoring API compatibility and speed etc. (numcl doesn't talk to BLAS/LAPACK IIRC), even the basic datastructure isn't quite there. Numcl uses fixed contiguous lisp arrays as opposed to the strided ones that are standard in Numpy.

P.S- There are atleast 5-6 attempts to build something of the sort starting all the way back from Matlisp, and none of them are feature complete.

The lisp curse is very much true it'd seem.


Check out numcl, it's numpy in common lisp!


That was a wonderful comparison. Thank you. - I had some contact with Scheme twenty years ago, while working through SICP. As I recently made a deep dive into Emacs and Emacs Lisp, I started looking into Common Lisp as well. - I absolutely love programming in Lisp. And like you, Scheme‘s clean naming convention (`set!` for destructive operations, `foo->bar` for conversions and `string?`) were something I missed in other languages in the years to come (when I started learning Python was irritated that `data.sort()` was a destructive operation). Scheme‘s spec is so short, I could keep it all in my head.

Lambda calculus, list manipulation, list operations, closures, these are concepts I learned twenty years ago learning Scheme, and I‘ve seen these concepts slowly be adopted in other popular languages decades later.

Thank you for catching my interest in Scheme again! Will look into that in more detail. Was an old love of mine anyway. :)


If you're looking for a Scheme with a very active community these days a and production oriented packages, Chicken is a strong choice.


My (not well researched) understanding was that Racket is a popular Scheme variant. But thanks for pointing towards Chicken Scheme.


Racket is great, and is now able to run on Chez Scheme as the backend. But as far as using it for production code, it's a bit problematic as the folks in charge are focused on it as a research and education tool first and foremost, meaning they are not shy about changing things a lot. Chicken compiles down to C and has a really friendly community with great docs and examples for "real world cases"


I tried scheme, but I couldn't live without a hashmap in the language. Thankfully, clojure specifies one as well as a uniform `seq` interface for collections.

The big problem is Clojure is a language without a published standard.


You might like S7, it has a lot of the high level features of Clojure in a scheme. (hashmaps, keywords, environments, Clojure/CL style macros.) This is what I am using these days.


I'm curious as to why they didn't mention Racket—perhaps they've just never heard of it.

My first programming language was Perl. After Perl came a little bit of C, but then I soon switched to Common Lisp. I wrote a lot of Common Lisp: I programed a text-based adventure game engine ala Zork entirely in CL! After reading Paul Graham's On Lisp and learning about Scheme, I took a look. My dad got me a PDF of SICP; I learned to prefer the Lisp-1 style of Scheme to the Lisp-2 style of CL.

I've done a bit of Clojure—I feel like Clojure does a better job of making data structures more ergonomic than either Scheme or CL.

I've recently started working more in Racket and I am loving it. It feels like a Scheme with a more visible, vibrant ecosystem. (Could just be me not being aware of the Scheme ecosystem—I was only 15 or so at the time I started writing Scheme.) Racket is definitely optimized for building DSLs. But I feel like the standard library is a bit better documented and easier to work with.

Just my experience though. I could be totally missing out on some great Scheme libs.

At the end of the day, Lisp in all its flavors is great, and I want to write as much of it as I can in my career.


FWIW, my first lisp was one called PLT Scheme. Most people know it as Racket nowadays.

There's been a couple decades' worth of divergent evolution since then, so that it's not actually compatible with any Scheme standard anymore. At least not by default -- there's still "#lang r5rs". In any case, one could be forgiven for thinking Racket is still just another flavor of Scheme.


I agree about Racket. While various lisps occupy specific niches, I feel like Racket is the lisp that checks the most boxes—especially for someone getting started and shopping around for the “right” lisp.


I prefer the syntax of CL over Scheme, but the latter is definitely a wonderful language and goes hand in hand with the wizard book, SICP.

At the end of the day, language choice, much like choice of editors or mechanical keyboards, is not that important — what is important is actually coding and building useful software. This can be done in any language, although I do not want to sound ignorant, as certain languages are better suited for certain tasks (eg swift for iOS dev).

As a Mac/Windows user, I’d be keen to know how popular Guile is for GNU Projects?

For those who want to learn Common Lisp quickly, this is a great guide: https://github.com/ashok-khanna/common-lisp-by-example


GNU Guile is the expression language for Guix (perhaps its major distinguishing feature, when compared to Nix, which uses its own bespoke language).


Thanks! Guix sounds pretty cool, I just did a cursory read of Wikipedia after your post.


I love Scheme, but it _badly_ needs call/cc replaced with delimited continuations.


The ease of implementing call/cc early on when you have a trivial interpreter is dangerous - it becomes far too easy to end up not realising you've made a rod for your own back until way too late.

A spec entry for delimited continuations with call/cc as an -optional- feature would definitely seem like an improvement in terms of leading implementors down a saner path.


What is the difference between call/cc and delimited continuations?


The fully-general continuations that call/cc creates require copying chunks of the stack to the heap for storage and back again when they're used. (Or pointing the stack pointer at the heap, which I find even more cringe-inducing.) They're memory hogs whose lifetimes are hard to reason about and they provide relatively little benefit to most programs, which is why Common Lisp doesn't provide them.


My main interest: delimited continuations are only valid within a specific stack extent so they're much for viable for extensive use - one could argue that async/await is kinda the simplest (and most limited) possible delimited continuation implementation.

For a better understanding, https://en.wikipedia.org/wiki/Delimited_continuation didn't feel like a terrible start and I'm far from an expert here.


Oooh: in addition to my other comment. Don't trust me, trust Matthew Flatt when he talks at Microsoft Research: https://youtu.be/IKddmXjYa5U

It contains a very telling comparison about delimited vs undelimited continuations and sows quite clearly by you always want delimited ones.


They are faster, easier to reason about, less prone to leak memory and are always what you want. Everyone except maybe the chicken scheme people agree, but call/cc is free for them due to their GC strategy.


Chicken and Cyclone share the same gc strategy.


Delimited continuations, a.k.a composable continuations, are. a generalization of control operators such as call/cc.

https://en.wikipedia.org/wiki/Delimited_continuation


Guile implementation of prompts (the guile name for delimited continuations) is the one I prefer the most among the schemes.


"I prefer the syntax of CL over Scheme"

Can you elaborate on what it is about CL syntax that you prefer over Scheme, and why?


Honestly I am no expert and my opinion holds no weight. I just don’t like the use of ? and ! in Scheme. Very much a personal preference


That's not even part of Scheme syntax.

It's just a convention that you're free to ignore in your own code.


Nitpick: the latest standard is R7RS-small (https://small.r7rs.org), which is (expectedly) smaller than R6RS. I believe it was supposed to be accompanied by something like R7RS-large, covering the rest of what is expected in a Scheme standard to succeed R6RS.



> Then again, in Common Lisp it’s somewhat rarer to have C extensions, so I don’t know how ASDF handles that.

CFFI

https://common-lisp.net/project/cffi/


Besides CFFI there's also cl-autowrap and claw. I haven't used claw myself, but I know cl-autowrap makes wrapping C libraries really easy. It took me about 4 hours and <200 lines of code to have a complete, usable binding for GDAL, and most of that was in convenience functions.

I'm curious to see what happens with the C++ support in claw. They're working on it, but I'm skeptical. I haven't had much luck using arbitrary C++ libraries from any language other than C++.

And I don't know what the author means by "somewhat rarer" in this context, but I personally use C libraries from CL all the time. Almost every CL project I work on, now that I think about it.


:claw author reporting in. At first, I was semi-skeptical too, but not anymore. I've managed to wrap a few C++ libraries (GLM, Filament, PhysX). Not without a manual intervention (claw is still evolving and adapting to C++ edge cases), but those libraries pretty much work now. I'm not sure I would be able to cover all C++ idiosyncrasies, but huge parts are already in.

That said, claw's C++ support is still in the works and I don't recommend diving into that mess yet. Stay tuned for Q1 2021 semi-usable alpha release. Or not. C++ is such a pile of shinies, I'm pretty sure I lost a few screws during :claw development.


I'll have to take another look!

Very surprised to see GLM in that list!


Rarer? How? Why? I know multiple people who do it daily. A lot of Lisp code directly depends on foreign libraries.


Actually I was talking about how to bundle C code with a Common Lisp library (or system), so that ASDF could also handle building it.

Guile has a C API in libguile, so you can create C that's directly callable from Scheme with little overhead. You can write Scheme procedures in C and you don't need to gobthrough FFI.

As far as I know both languages have FFI. CL has CFFI, Guile has it in its standard library.

But can I actually ship some C code with my CL system and have ASDF take care of building it? If I want to ship CL bindings for a C library, as far as I've understood I need to tell users to install the library first. Maybe something like Clasp offers a C++ API?

Then again in both languages you can always use FFI and if things get hairy you can use grovelling.

With Guile, it's really easy to have a C library and package its guile bindings in the same place. Not saying you can't do this in CL, just that I don't know what it would look like to ship both C and CL in the same package.

(author)


Someone requested to add a project to Quicklisp; that project does just what you describe. See the ASD file for details.

https://github.com/tdrhq/cl-unix-sockets


a bit about the context:

Guile is an extended specific implementation of Scheme. Common Lisp OTOH is a language standard with widely different implementations. Just like Scheme has very different implementations - in sizes of small, medium and large.

Common Lisp with more extensive C extension support are CLISP (written in C, not that well supported nowadays), ECL ('embeddable Common Lisp', compiling to C), CLASP (integration with C++ via LLVM), mocl (commercial whole program compiler to C) and a bunch of others.

Thus the support of and integration into is different in Common Lisp implementations, just like it is different in Scheme implementations. GUILE was designed for C embedding, just like some Common Lisp implementations were designed for that task. Guile was also designated as a language of choice for the GNU project, which adds quite a bit community support - while Common Lisp (or one of its implementation) was not:

'Guile is the GNU Ubiquitous Intelligent Language for Extensions, and the official extension language of the GNU project.'


Yeah, this. I call C code from CL all the time. Also Objective C if I'm working with Clozure CL on a Mac.


In Guile, because it lacks an optimizing native code compiler, they write C extensions just to get their code to perform acceptably. In Common Lisp the only reason you'd use CFFI is if you needed to call some code that was written in C.


That's not quite true anymore: Guile 3.0 has an optimizing compiler and a JIT and it performs pretty well.

See for instance: https://wingolog.org/archives/2019/06/26/fibs-lies-and-bench...

Nowadays most Guile users write exclusively Scheme code, resorting to the FFI for code reuse rather than for performance reasons.


> That said, Common Lisp is weird. What I find particularly jarring is that functions and variables live in different namespaces: if you put a function into a variable, you can’t just use it like a function, you have to funcall it.

Unless I’m misunderstanding, the author sounds like a developer that’s primarily used JS. It’s really not abnormal to have to include parens after a method name in a language, which indicating that you are calling a function.


> It’s really not abnormal to have to include parens after a method name in a language

That's not what he means. Assuming some pseudocode with a more common syntax to prune the parentheses question, Common lisp is doing this:

    function f(x) { print(x) }
    let a = f
    funcall(a)(27)  # prints 27
Whereas Scheme is doing this:

    function f(x) { print(x) }
    let a = f
    a(27)           # also prints 27
This is the fundamental difference between so-called Lisp-1 and Lisp-2 families, depending on whether functions and variable share the same namespace or if they have to be “lifted” from one to another through funcall.


I think you are misunderstanding.

In common Lisp you can call a regular function defined with defun as (foo "something"), but if bar is a variable containing a fuction you have to use (funcall bar " something"). I agree that this is weird and confusing.


Isn't that the same thing as using function pointers in C?

You need the * to access the function the variable points to.


No you don't. You call the pointer itself. It points to the first instruction in the function.

It's more like Ruby's method(:foo) and .call().


Sure, this isn't that rare of a thing for languages, but it is increasingly rare to find people who think this is a good idea.


The piece has the usual complaining about CL being a Lisp-2.

When I ask to have the advantage of a Lisp-1 explained to me, I get some handwaving about "elegance", rather than a specific explanation for why someone would want that. Personally, I find a Lisp-2 (or a Lisp-N) to be more convenient and more understandable. And I don't have to have lexical variables named "lst".


Saying that it's weird (which it is - I have a really hard time thinking of other languages that do this) and then pointing out that there are good reasons why it's that way, and linking an article explaining them, and then explicitly saying, "this isn't a fault, my comfort zones are a product of what I already know," isn't exactly complaining. It's possibly the most measured, non-partisan response to the whole lisp-1 vs lisp-2 thing I've ever seen.


Java is a Lisp-2; method names exist in a separate namespace from values (although, there may be semi-arbitrary restriction of name collisions): foo.toString doesn’t give you a “function object”.


> I have a really hard time thinking of other languages that do this

Ruby, PERL, R, Shell languages, Elixir.


The most basic reason for wanting a Lisp-1 would be to make code more context-free. "foo" refers to "foo", and you don't have to be aware of whatever special underlying context is there.

The closest parallel I can think of is Scala implicits. You give me a fragment of Scala code using implicits it might be hard to know _what_ is going to happen. Similarly, having a bunch of namespaces (or, perhaps more importantly, leaning into them and having many name overlaps) just means that it's harder to read a single code fragment and know what it's going to do.

Though I'm pretty partial to the argument that, like..... yeah you're going to call a function so the name refers to a function. But without extra symbols around this concept to help the reader, in this age it seems like a concept that is hard to take advantage of.


I don't know if it's a "reason" or not, but lisp-1 semantics would be more familiar to a language that legions of programmers would be familiar with - JavaScript. Eich wanted to make Scheme for the web, and having a variable containing a function, no matter where it's placed, would be the least cognitive distance from what people are used to.


The context is basically

  (here ...
versus

  (... here ...
That's what makes possible the two spaces.


There's a discussion of the relative merits of Lisp 1 vs Lisp 2 (or higher) in Technical Issues of Separation in Function Cells and Value Cells by Richard Gabriel (http://www.nhplace.com/kent/Papers/Technical-Issues.html).


> When I ask to have the advantage of a Lisp-1 explained to me, I get some handwaving about "elegance", rather than a specific explanation for why someone would want that.

It encourages programming more in a functional style. It's much easier to implement and use higher order functions, if functions are treated like any other object. In Common Lisp, functions defined with DEFUN are not, by default. Common Lisp supports the functional style, but in order to operate on functions with higher-order functions, you must first scoop them out of their special namespace with FUNCTION; and if you want to apply a function you have as a value you must FUNCALL it.

Lisp-1s remove these extra steps, and to some programmers that is more understandable.


Much easier, in the sense that you don't have to type #' to get from the function namespace to a value. Oh no, I had to type two characters.

As for going in the other direction: I examined the Quicklisp source for how often funcall occurs: on about 0.4% of lines.

I will claim that adding these makes the code more understandable, not less.


> you must first scoop them out of their special namespace

So

(mapcar #'f list)

instead of

(mapcar f list)

?


> Clojure isn’t a true Lisp, or well, it is part of the Lisp family, but its extra syntax. Its ability to interface with the JVM makes it easy to leverage the thousands of JVM libraries out there.

Doesn't ABCL let you do the same?


I am often wishing I knew of an easier way to compare Lisps. I haven't used any dialect enough to fully grasp the subtleties. For example, the differences between Racket and Clojure.


Probably the main difference between Clojure and all the rest, from a purely lispy perspective, is that it's not list-oriented. Maps are its preferred data structure. I'm not even sure it has cons cells - at the very least, I've never seen them being used.

Probably the main thing that distinguishes Racket is that it's meant to be a playground for experimenting with programming language design.


Clojure is really designed around the sequence abstraction, which is list-like but not a list: Clojure’s various concrete datastructures all implement this abstraction and, consequently, much of clojure.core is more generic than the equivalent functions in the CL package: maps present as sequences of pairs; vectors, sets and lazy sequences all present as sequences of items, etc.


Clojure is oriented towards functional programming, hence no loops, but because it's also a thin abstraction over the JVM, it doesn't provide tail-call elimination, so you can't write traditional functional code the way you would in SML or Scheme. Instead, you have to use the clumsy "recur" construct to work around the JVM's limitations.

It's also less consistent than proper Lisps. For example, it's possible to produce a Java OverflowException using Clojure math operators. Some operations will gracefully upgrade to bignums, but others don't.


Any good guides on how to get started in Lisps, from a programming languages theory perspective?


There's Lisp In Small Pieces by Christian Queinnec (https://www.amazon.co.uk/Lisp-Small-Pieces-Christian-Queinne...), and if you want to look into CLOS in depth, there's The Art of the Metaobject Protocol by Kiczales, des Rivieres, and Bobrow (https://www.amazon.co.uk/Art-Metaobject-Protocol-MIT-Press/d...). There's also a good older text, Anatomy of Lisp by John Allen (https://www.amazon.co.uk/Anatomy-LISP-McGraw-Hill-computer-s...).


I am finishing up teaching an undergraduate-level course on programming language principles and paradigms.

Here is what I recommend:

1. Study Scheme for an introduction to programming in a Lisp-like language. I used Structure and Interpretation of Computer Programs as one of my course textbooks (I also assigned my students separate textbooks for the Prolog and Smalltalk portions of the class). My favorite part of this book is its discussion of the metacircular interpreter (i.e., a Scheme interpreter written in Scheme), which is key to understanding how a Lisp works internally.

2. Read the Lisp 1.5 Programmer's Manual. While this Lisp has long been succeeded by more modern Lisps, it is a very nicely designed manual that discusses the implementation of Lisp. It also has a short metacircular interpreter on page 13 that profoundly inspired Alan Kay and many other luminaries of computer science.

3. Begin learning Common Lisp. Common Lisp is much more complex than Scheme is; Common Lisp is to Scheme as C++ is to C. I started getting serious about learning Common Lisp earlier this year, and I am currently working through the Advent of Code exercises in Common Lisp. My favorite intro book is Common Lisp: A Gentle Introduction to Symbolic Computing. I also own a copy of Common Lisp Recipes, which has been valuable for learning Common Lisp idioms; part of the challenge of learning a large language is figuring out what are the most idiomatically correct ways of doing things.

4. Read The Art of the Metaobject Protocol. I have a copy of the book, but I haven't gone through it yet. My goal is to work through this book to have a full understanding of the Common Lisp Object System.


Regarding 4, I'd suggest reading Object-Oriented Programming: The CLOS Perspective first. It also has a great cover (same illustrator as AMOP), though it's not evident from Amazon's page last time I checked. This book is really a big collection of papers from several authors. It covers the topics of Lisp's OOP system and some of its history, its unique features (especially some comparison chapters with C++, Smalltalk, Eiffel), its meta-object protocol (and why you'd want it), some production reports from the field on its use in helping application development, and some implementation details to ward off "surely this is sooo much slower than a plain old function call?"


What textbooks did you assign for prolog and smalltalk?


I used The Art of Prolog, Second Edition by Leon Sterling and Ehud Shapiro (https://mitpress.mit.edu/books/art-prolog-second-edition), which is available for free using the "Open Access" link, and also Smalltalk-80: The Language and Its Implementation by Adele Goldberg and David Robson (http://stephane.ducasse.free.fr/FreeBooks/BlueBook/Bluebook....), which is also available legally for free with permission (see http://stephane.ducasse.free.fr/FreeBooks.html for other freely-available Smalltalk books that are out of print).


Thanks!


I really liked Practical Common Lisp by Peter Seibel ( https://gigamonkeys.com/book/ ) however, ignore the environment setup: the recommendations it makes are no longer maintained, these days Portacle is the best way to get started.

One thing I really like about this book is it assumes you know basic programming ideas, so it gets into distinctively “lispy” features relatively quickly. The chapters on exception handling and Common Lisp’s object system, in particular, really sort of blew my mind and had a fairly profound influence on the way I think about programming languages.


> I really liked Practical Common Lisp by Peter Seibel ( https://gigamonkeys.com/book/ ) however, ignore the environment setup: the recommendations it makes are no longer maintained, these days Portacle is the best way to get started.

A bunch of us from Freenode IRC have formed Common Lisp Programming Challenge (CLPC) at https://github.com/spxy/clpc in order to help beginners get started with Common Lisp (CL) while learning the language from Practical Common Lisp by Peter Seibel.

The outdated environment setup in the book can indeed be a genuine hurdle for a beginner. Portacle is a great way to get started. In the CLPC repository though, we are documenting the steps to set up Emacs, SLIME, etc. from scratch, so that a beginner to the CL ecosystem can try out and understand the traditional way of installing and setting up these tools.

If anyone here comes across this comment and is already reading or about to start reading the book Practical Common Lisp, or is eager to learn Common Lisp, you are welcome to visit https://github.com/spxy/clpc and join the Common Lisp Programming Challenge.


Yeah, it's all tradeoffs, Portacle has the advantage of not requiring you to learn emacs as much to learn Common Lisp.


Hmm, maybe this isn’t the best for PLT: for that, I’d recommend the Art of the Metaobject Protocol which is a really interesting case study in the design of the implementation of a fairly complex part of the CL standard.


[1] and [2]. [3] is a good intro in a more practical perspective.

1: http://www.eopl3.com/

2: http://cs.brown.edu/courses/cs173/2012/book/

3: https://ds26gte.github.io/tyscheme/


Time to make a new Lisp!


Have you tried newLISP ? http://www.newlisp.org/ I am having a lot of fun with it. I'd call it a 'practical' LISP.


I was expecting Clojure vs Common Lisp. I love scheme but it's not fair to include considering how few libraries there are (I don't even know if there is a package manager).


Maybe typing "scheme package manager" on google and clicking the very first link would help?


I remember reading about Raven when it came out for Cisco Scheme. I totally forgot about chicken scheme. I just remember being interested in Guile and sad that only guildhall was available.


Racket has tons of packages and I believe it has everything he talked about (keyword arguments, etc.).


I also managed to completely forget about Racket. I was thinking only of Guile like an idiot.


The article mentions GNU Guix as "the" package manager for Guile Scheme.

Now, Guix includes some 15000 non-Scheme packages, so it is somewhat "overkill". OTOH you can also install/run/dockerize a world of Common Lisp packages with Guix. :-)


Guix is a package manager written in scheme, but as the article states they are considering how to use it for guile if they do.


The article mentioned at least two scheme package managers: chicken-install and GNU Guix.




Consider applying for YC's Summer 2026 batch! Applications are open till May 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: