Hacker News new | past | comments | ask | show | jobs | submit login
CL21 – Common Lisp in the 21st Century (github.com/cl21)
98 points by eruditely on Jan 11, 2016 | hide | past | favorite | 40 comments



As someone who writes CL for fun, I think all "let's get the core language (any language) API right this time" efforts are ultimately doomed to perdition and entropy.

I'd rather have an API that's not quite perfect, but has had much thought and wisdom put into it, and is as stable as continents, than an API that's always iterating towards some unreachable Platonic idea of perfection.

As an aside, the author has also created a -- likely more agreeable -- spin off library that's a simpler interface to cl-ppcre: https://github.com/fukamachi/re21


I am currently learning common lisp. The only thing I've really found lacking is support for basic string operations. I'm sure there is a solid library out there for things like replace(), but it seems silly for everyone to possibly be using separate libraries, or in-house implementations for standard string operations. It creates an unnecessary barrier to code readability. From what I've heard around the grape vine, this is a result of the ANSI standard being released prior to the popularization of these functions in other languages. If the CL specification is ever updated, I am sure that this problem will be solved. I am surprised this github project didn't acknowledge this.

P.S. Changing the name of 'Remove-if-not' makes absolutely no sense to me. Remove-if and Remove-if-not make perfect sense together. Adding a whole new word to memorize "Keep" just makes code less readable. Especially since Keep isn't seen anywhere else in the language. Further-more the redundancy in the names 'remove-if' and 'remove-if-not' make you think about how these functions are actually the same, with only a small caveat. 'remove-if' and 'keep-if' make you think of these functions as different things, as different ideas, very unlispy.

edit: just checked cl-ppcre's documentation and learned that split and replace are covered by that lib. Seeing as cl-ppcre seems to be used so widely, I take back what I said. Lisp is perfect once again.


> The only thing I've really found lacking is support for basic string operations. I'm sure there is a solid library out there for things like replace(), but it seems silly for everyone to possibly be using separate libraries

It's not that bad, there are other languages which have this problem - you can see exactly the same situation in JS-land, for example. It would be much worse if not for quicklisp. I think quicklisp and asdf are among the best package distribution tools: I feel it's better than pip and gem and similar to npm. Installing a library is literally a single line in your code. There's the problem with finding the package you need and it's harder than with JS and npm, but doable.

BTW: what do you do to learn CL? I'm using StumpWM as my window manager and I think it's one of the best ways of learning CL. With SLIME, then, you get almost Lisp-only environment, especially if you use Emacs for your other editing too. I wrote a couple of blog posts[1] about StumpWM and posted my config on GitHub[2].

[1] https://klibert.pl/posts/stumpwm.html https://klibert.pl/output/stumpwm-better-modeline.html

[2] https://github.com/piotrklibert/stumpwm-config/


If you already know another programming language, you can try PCL[1]; it's a decent introduction. If you get stuck on something feel free to ask on IRC (#lisp on freenode).

There is a library called alexandria[2] that covers a lot of obvious missing-features from the standard library (e.g. emptyp to test for an empty sequence).

Lastly the hyperspec[3] is actually quite useful as a library reference.

1: http://gigamonkeys.com/book/

2: https://common-lisp.net/project/alexandria/draft/alexandria....

3: http://www.lispworks.com/documentation/HyperSpec/Front/Conte...


> what do you do to learn CL?

The best thing I've done is watch a video on making a reddit clone in Lisp. I couldn't get the libraries to work, but I plan on using other libraries to do the same thing either tomorrow or the next day. It's made me realize that I really need to start walking through other people's code. https://vimeo.com/138249727

Google's LISP koans which is ~30 exercises where you complete the code and make the tests pass. Covers everything from mapcar to multi-threading. https://github.com/google/lisp-koans

I'm currently on Ch. 9/32 of Peter Seigel's "Practical Common Lisp". I find the book to be a much better resource after already being familiar with the topics covered. It does a great job of going into the nuances and gotchas of the language, but because is so much more text than code, it's hard for me to appreciate all of those little details if I'm still trying to grasp the fundamentals of the topic. http://www.gigamonkeys.com/book/

I write all the code I see with a pencil and paper (including all of those koans). I read a block of code and then try to rewrite it from memory.

Currently using vim. Haven't gotten around yet to using a live environment.

  Future resources:
    Paul Graham's "Roots of Lisp"  
    Paul Graham's "On Lisp"  
    Build a Lisp compiler  
    SICP  
    Paradigms of Artificial Intelligence Programming
    Upgrade my editor
Yeah, there's a lot I want to go through. It's gonna take me a few months just to go through all of the resources I have bookmarked so far. And I haven't even started looking for code that I want to read. End goal is to master Lisp.


It's all there with libraries, if you hunker down. I came from Perl so yes it's harder.

Library-wise, CL-PPCRE and SPLIT-SEQUENCE are your friends, along with a bunch of the sequence operations in the ANSI spec, and finally, you should get comfortable doing some string stuff in LOOP going char by char or word by word.


I like UIOP:SPLIT-STRING instead of SPLIT-SEQUENCE.


Thank you.


The problem with the name 'remove-if-not' is that it's both more fundamental and much more common in actual use than 'remove-if', yet its name is both longer to type and conceptually more complex.

Selecting a subcollection of elements that satisfy a predicate is a natural primitive. My favorite name for it is 'filter'; that's what I've called it in FSet [0]. I haven't defined 'filter-not'; usually the predicate is an explicit lambda expression, in which case adding the negation is straightforward, and even when a lambda is not needed, it's easy enough to write something like '(filter (complement #'integerp) ...)'.

Anyway, even though I prefer 'filter', I could live with 'keep-if'. And by the argument I just gave, we wouldn't really need 'remove-if' anymore. The problem is 'delete-if'/'delete-if-not'; what do we do with them? I guess I would rename 'delete-if-not' to 'nkeep-if' (by analogy with 'nreverse' and 'nsubstitute') and discard 'delete-if'.

[0] http://ergy.com/FSet.html


I completely disagree. Remove-if-not is explicit. You know exactly what it does just by reading it. Your suggestion of filter could either mean use this filter to only grab the the things I want or use this filter to filter out the things I don't want. Complaining about the complexity of a name like "remove-if-not" makes absolutely no sense to me. Anyone can read that name and know exactly what it does. You only know what filter means because of your familiarity with it and not because of any inherit simplicity in its name.


FYI, in Arc, the corresponding functions to "remove-if-not" and "remove-if" are called "keep" and "rem".


It was later thought that one better writes

    (remove-if (complement #'prime-p) ...)
and not

    (remove-if-not #'prime-p ...)
and thus REMOVE-IF-NOT was deprecated in the ANSI CL standard.


And don't forget to check out cl-interpol. Besides being a perfect companion to cl-ppcre, its great in itself if you like things like string interpolation.


Currently there is an effort in GNU Emacs project to move a subset of Common Lisp in Emacs Lisp under the cl prefix, so one would say cl-let or cl-values, etc.

It seems like a cool idea. If you disagree with some of CL's design or stylistic choices, which people familiar with Arc or Scheme would do, moving it out of the way is a good idea.

BTW, a long ago in order or incorporate CL into Symbolics Zeta Lisp they used cl: prefix for some functions. Nothing is new under the Moon.)


> BTW, a long ago in order or incorporate CL into Symbolics Zeta Lisp they used cl: prefix for some functions. Nothing is new under the Moon.)

'cl:' is no prefix in Zetalisp. Zetalisp uses packages (namespaces for symbols) just like Common Lisp, and 'cl' is the name of a package and ':' is the separator from package name and symbol name. A single colon shows that the symbol is exported - some part of an external interface.

Thus cl:let is the 'let' exported from the 'cl' package.

Emacs Lisp has no packages, no namespaces, no exports, imports, ... So 'cl-' is a part of the symbol name. It's just a prefix.


Yeah, sorry. Having separate namespaces for packages is much better and prefixing is just naming conventions.


The reason there are adding the cl-prefix in cl-lib is that previously cl.el replaced elisp functions with the cl equivalent ones.

lispm already covered that cl: is packages, not a prefix but I'd like to add one of the reasons elisp doesn't have any similar of namespaces is due RMS thiking "prefixes are better"[0]

[0]: https://lists.gnu.org/archive/html/emacs-devel/2013-07/msg00...


What on earth happened to this project? It looked really promising. Is it all left to racket now?


For me personally, I'm already used to the ugly CL syntax that it's working around (hashes), already familiar and comfortable with the underlying libraries it's using (cl-ppcre, etc.), or don't find the features particularly useful (laziness, etc.).

TBH, if I found those things annoying enough to seek out this library, I would probably just use Clojure or some other language.


That's the problem with any CL cleanup project: it's mostly going to appeal to newcomers to CL, who don't already have a large code base in the language, full of their own macros that address at least a few of the same issues.

Not that CL couldn't use cleaning up. But to really make the new dialect popular, you'd have to focus on attracting new users, which would require things like writing books, or at least updating some of the existing books (e.g. Peter Seibel's). In short, defining and implementing the new dialect is only the first step of a long slog.


> mostly going to appeal to newcomers to CL ... you'd have to focus on attracting new users

It's my observation that CL regularly attracts new users, who grumble a bit at first and then fall in love. Then they drift away to other langs, keeping an affection for sexps, macros, and the numerous elegant aspects of CL. But drift away they do. IMO, if CL could keep more of the people who learn it well enough to love it, then it would be thriving. I have some opinions on why people drift away and how that could be addressed but they're not especially well formed at this time.


This is pretty close to my story. Had a lot of fun programming CL. Even worked with "His Kennyness" and Hans Huebner for a while. But I was young and needed to experience different dev cultures so I went and did some Rails for a while.

I dream of meeting someone who wants to build something like mesos on top of cells.


> I have some opinions on why people drift away and how that could be addressed but they're not especially well formed at this time.

I would like to hear them nonetheless.


I would rather not say until I've thought it out some more. A bag of mushy thoughts with a grain of truth in them would probably be provocative and wouldn't provide much utility for the CL community.

Instead, here's one of the things that started me thinking about this... Some years back, Xach created the library manager Quicklisp, filling a huge hole in the lisp ecosystem. It's nice work and quickly became the defacto standard. Lots good to say about it and nothing bad, really. The thing that got me thinking was that this actually needed to be done at the time Xach did it. CL had been around a long time officially and even longer unofficially, and this really important piece of infrastructure had not been done. How could that be?

"How could that be?" leads to more questions, and possible answers, and some loose ideas about moving forward. That's where I'm at, and I don't want to say more until I have something concrete and constructive. I wouldn't mind having a speculative conversation (that would help me greatly), but I think throwing out half baked ideas would do nothing more than the existing corpus of "why lisp isn't successful" blog posts, so I don't want to have that conversation somewhere like HN.


Speaking of books, have you by chance read Weitz's new one? https://www.apress.com/9781484211779


Worth it.


Common Lisp has a standard. The most recent major work on standards may be ISLisp.

http://www.islisp.info/

Creating a consensus language specificatoin is hard. It takes a community of people willing to work over a long period of time in very detailed ways. Throwing a proposal up on Github is unlikely to create a community and organization with the required commitments.


I'm surprised all of the modern attempts at Lisp don't provide some kind of docstrings (i.e., JavaDoc-like documentation as a first class object available in the REPL). Why isn't that something that everyone expects in a modern language?


If I'm understanding your question correctly, that's been in there from ANSI CL. For example, when defining a function, after the lambda list, a string will be interpreted as a docstring and stored with the function definition.

http://www.lispworks.com/documentation/HyperSpec/Body/f_docu...

    (defun test ()
      "A test function"
      (+ 1 1))
    => TEST

    (documentation 'test 'function)
    => "A test function"
You can statically analyze source code to pull them out, or ask the Lisp image for them, etc. Is there something missing?


Ah. I see. It wasn't obvious in either the examples or the source code.

I would like to see more structure: expected arguments, return type, etc.


Why would you do that in a doc-string? If you just `declare` the types with `declare` instead of putting them in the docstring, the compiler can also take advantage of them. Then the system can automatically tell you that information back. It will also infer the return type for you automatically.

A trivial example (your editor can do this for you):

    (defun add-string (a b)
      (declare (number a) (string b))
      "Parses b and adds to a"
      (+ a (parse-integer b)))

    CL-USER> (describe #'add-string)
    #<FUNCTION ADD-STRING>
      [compiled function]
    
    Lambda-list: (A B)
    Derived type: (FUNCTION (NUMBER STRING) (VALUES NUMBER &OPTIONAL))
    Documentation:
      Parses b and adds to a
    Source file: /home/bja/foo.lisp


There is also ftype:

  (declaim (ftype (function (number string) number) add-string))
  (defun add-string (a b) ...)


Ah. That's nice. Thanks for pointing that out. That's something I've not seen in any introductions to Common Lisp.

Are all of the standard functions documented this way?


I think so (at least on sbcl). I don't use common lisp all that much, I mostly knew about describe due to the which-key menus in the emacs SLIME environment.


Why not check your favourite implementation's source?


I have perused the source for Steel Bank Common Lisp, but it's far from clear if everything in the standard is documented this way or if one must keep a tab open to the Common Lisp specification for such references.


You can query the argument list using function-lambda-expression[0], or by code injection[1].

If you mean structure within the docstrings, there's no official standard, but markup languages for that exist, see Codex[2].

[0]: http://clhs.lisp.se/Body/f_fn_lam.htm

[1]: https://github.com/eudoxia0/docparser

[2]: http://commondoc.github.io/codex/


There are longstanding conventions for how to write those, same as with other languages or automatic document generation tools. Search for "lisp docstring style" or something to that effect. Here's a possibly non-authoritative example from the Emacs Lisp community:

https://github.com/bbatsov/emacs-lisp-style-guide#docstrings

Edited to add: Documentation strings actually predate Common Lisp. They were available at least as early as Zetalisp (mid-1970s).


Huh?

Emacs, Guile, and the common lisp in this project have doc strings?

What implementations are you referring to, and what features do you think they're missing?


As I replied to martinflack, I was expecting to see it in the examples or source code. It wasn't obvious that it's inherited from the implementation language.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

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

Search: