16 ms·
Modern, functional Common Lisp: myths and best practices
- atgreen 7y agoCommon Lisp is also a pleasure to use for k8s-hosted services. Just deploy your Lisp-based service to k8s, forward the sly/slime port to your local system, and continue to work on it interactively with emacs and sly/slime. It's really the most interactive development approach for k8s-hosted services. See https://github.com/container-lisp/s2i-lisp https://github.com/container-lisp/s2i-lisp
- lvh 7y agoHow do you do the forwarding? (That’s an interesting question to me by itself, but I ask because it seems like that feature is just as good outside of k8s too :))
- simiones 7y agoWith k8s, you just create a service of type NodePort and it assigns a free external port for that service, which is mapped back to a specific port in the Lisp container.
- lvh 7y agoI know of NodePort, but last i checked it’s a low-level constrict that doesn’t do anything like, say, authn—so that doesn’t seem like a complete answer.
- ohithereyou 7y agoWhat sort of encryption and authentication can I expect if I do that? Can anybody who guesses the port dump code into my running Lisp instance?
- e12e 7y agoThis is entirely to hard to find the answer to in the kubernetes/kubectl documentation. Apparently the forward is done via socat over tls: https://stackoverflow.com/questions/50645059/is-kubectl-port-forward-encrypted https://stackoverflow.com/questions/50645059/is-kubectl-port... And socat is mentioned in: https://github.com/kubernetes/kubectl/blob/master/pkg/cmd/portforward/portforward.go https://github.com/kubernetes/kubectl/blob/master/pkg/cmd/po... I didn't actually manage to find out what or how socat is called - but I'm also on mobile, so it's a little convoluted to browse source code. Anyone know where the call to socat happens, after kubectl port-forward?
- simiones 7y agoThe encryption and authentication that the Lisp image exposes :) Someone else mentioned that kubectl port-forward also adds these for you, so if you are not in a private cluster, it may be a better option.
- atgreen 7y agoDon't do this... You only need the connection for development purposes, so use "kubectl port-forward", which gives you the auth you'll need as well.
- messe 7y agoOutside of k8s, which I'm not familiar with, ssh can do port forwarding.
- lvh 7y agoSure, I know general techniques and k8s-specific ones (and have used production SSH-to-programming environment REPLs with twisted). I’m asking partially because my job these days is to secure setups like these :)
- ivan4th 7y agokubectl port-forward my-lisp-pod 4005:4005 then M-x slime-connect localhost 4005
- atgreen 7y agoivan4th had the right answer. Use the "kubectl port-forward" command. BTW, here's a k8s-hosted app I wrote using this approach: https://github.com/atgreen/red-light-green-light https://github.com/atgreen/red-light-green-light
- vindarel 7y agoGenerally, here's how to connect to a remote running lisp image, and send changes from one's comfortable editor: https://lispcookbook.github.io/cl-cookbook/debugging.html#remote-debugging https://lispcookbook.github.io/cl-cookbook/debugging.html#re...
- chalst 7y agoI don't consider a language supportive of functional programming unless it supports tail-call optimisation, which is performed by some but not all implementations of Common Lisp. The article recommends SBCL, which does support TCO. An old (2011) survey of TCO support is at https://0branch.com/notes/tco-cl.html https://0branch.com/notes/tco-cl.html
- Ambrevar 7y agoIndeed, tail-call optimization is not part of the standard, unlike Scheme. The point of the article is that while the Common Lisp standard is not really focused on functional programming, nothing prevents the implementions (and libraries) of today to be so.
- armitron 7y agoAll the CL implementations that matter support TCO.
- pdexter 7y agoThat sounds more like an implementation detail, in most cases. By this metric Haskell wouldn't be a functional language.
- deleted 7y ago[deleted]
- nybble41 7y agoIt's a very important implementation detail. Explicit loops tend to imply mutation, which is contrary to idiomatic functional programming. Recursive calls don't require mutation but do require TCO to achieve equivalent space complexity. Constant-factor optimizations are one thing but failing to perform TCO turns constant-space algorithms into linear-space algorithms (or linear ones into quadratic, etc.). It's less a matter of "optimizing" the calls and more a matter of not wasting limited stack space on data which is clearly not required to execute the remainder of the program. One might as well label the practice of freeing stack frames when a function returns "Function Return Optimization" (FRO) and consider it a mere "implementation detail". After all, wouldn't it be much simpler to grab new memory every time the program needs some storage space and never bother with cleaning it up? It would certainly make debugging easier with all those old variables retained for the life of the program and not constantly overwritten by new data. However, programs written for a language without guaranteed "FRO" would look very different from normal programs, much as programs designed to compensate for the lack of guaranteed TCO look very different from idiomatic functional programs. Haskell uses a different (data-centric, non-strict) evaluation model where recursive definitions don't result in recursive calls, so traditional TCO isn't as relevant. Recursion is used very heavily in Haskell—which has no first-class looping constructs—but the resulting programs generally do not require large stacks. It's not unusual to be able to run even large Haskell programs with a 1 KiB maximum stack size (+RTS -K1k). Space leaks are possible, of course, but they take place in the heap.
- pfdietz 7y agoI've been doing some functional style programming in Common Lisp, and I was wondering what exactly should be considered functional programming. In particular, is object identity with EQ consistent with functional programming? Constructors do not act like functions if EQ is the equality. Or should that be more "immutable programming"? Common Lisp, because it has EQ and object identity, cannot perform some optimizations that a truly functional language's implementation could. In particular, it cannot combine equivalent function calls, and cannot merge equivalent data (hash consing or the equivalent.)
- Ambrevar 7y agoImmutability is something I'm still exploring in Common Lisp. Any pointer, anyone?
- TurboHaskal 7y agoWhat I do: Write pure functions, but don't shy away from mutating lexically scoped state in order to improve performance. For global stuff, wrap it with classes since objects are a commonly understood way to reason about state.
- Ambrevar 7y agoFor immutable data structures, there is this helper library which can help: http://quickdocs.org/immutable-struct/ http://quickdocs.org/immutable-struct/
- pfdietz 7y agoIt's a matter of not modifying things once constructed. CL has hooks to help do that, although a user can always get around them. A package I've been involved with lately is fset, which is available through quicklisp, or at https://github.com/slburson/fset https://github.com/slburson/fset It has some interesting features, including "functional setf expansion". This would turn something like (setf (fcar x) y) into something equivalent to (setf x (cons y (fcdr x))) (where "fcar" and "fcdr" are the same as "car" and "cdr", except when they are in a setf-able place form.) (fcar and fcdr are not in fset; I used those names just for exposition here.) It could work with nested accessors, but only if it bottoms out in a variable.
- chalst 7y agoAmusing set of quotes about CL by famous lispers: http://xahlee.info/comp/Common_Lisp_quotations.html http://xahlee.info/comp/Common_Lisp_quotations.html
- pjmlp 7y agoVery nice overview, I failed to see references to LispWorks and Allegro, though.
- TurboHaskal 7y agoWhich is a pity because at least for LispWorks, the IDE itself and the CAPI GUI toolkit could be considered killer apps.
- Ambrevar 7y agoI've never used them myself, so in all honesty I have nothing to say about them! :p That said, I support free software and I believe a proprietary compiler is not a good idea :(
- pjmlp 7y agoThe FOSS experience is a poor imitation of Lisp Machines.
- TurboHaskal 7y agoIdeology aside, most proprietary compilers (mostly for Forth, Pascal and Lisp) I have used are of _excellent_ quality. A lot also provide you the source code once you pay. AllegroCL is one of them I think.
- rgrau 7y agoOne little thing I did for Allegro was to compile their docs into a dash docset so you can use emacs' dash-docs with it. - https://github.com/kidd/AllegroLisp.docset https://github.com/kidd/AllegroLisp.docset - https://github.com/dash-docs-el/ https://github.com/dash-docs-el/
- mark_l_watson 7y agoThanks for writing that up. Common Lisp as a language and ecosystem is so huge that we all have our own view of what CL is and how to use it to build applications. I have been actively using CL since around 1982 for prototyping and also building applications and tools but I feel like I use a small part of what is available, mostly because I prefer to use what I am used to. I should should probably spend a little less time building things with CL and a little more time studying it. EDIT: off topic, sorry, but I have been actively evaluating CL (using an embedded web server that starts a browser) vs. Swift (using mostly SwiftUI) for a new product I want to write. I find myself using Swift like I would CL: using Playgrounds to prototype low level code and utilities, then XCode for developing the UI. To be honest, Swift and SwiftUI is a better fit technology-wise for what I want to do, but I am so much happier when working in CL.
- TurboHaskal 7y agoCan you elaborate why is it a better fit? Have you evaluated CAPI? Have you looked into building Cocoa applications with Clozure CL?
- mark_l_watson 7y agoCAPI is great, very well designed and implemented. The advantage of Swift and SwiftUI is that my application can run on both a MacBook and iPad, sync data with iCloud. The advantage of LispWorks is that I could fairly easily support both Mac and Windows (and Linux). I spent two evenings last week playing with Clozure CL and its Cocoa support. It has low level APIs and I had a peculiar issue with sometimes not being enter text into input components. EDIT: to be clear, in general I love Clozure CL. In this instance I was probably shooting myself in the foot, somehow, or maybe the issue was that I blew the install in some way getting it running on Catalina which took over an hour. The Catalina problems are hopefully just short term issues.
- fiddlerwoaroof 7y agoI haven’t used it myself, but EQL5 is attempting to make it possible to use ECL to iOS and Android apps
- tom-thistime 7y agoThis doesn't scratch my itch at all. I love Lisp but boring old Python has the libraries I need. EDIT: Based on a comment and downvote I suppose I didn't make my point clear above. I am saying that myths are not the only thing holding Lisp back. (I may be wrong. I hope I'm wrong. Big thank-you to people who are linking ways to get libraries in Lisp, especially Python libraries.) I care 10x as much about libraries as about all these red herrings (EDIT: or myths, as you like) combined: " * Common Lisp does not have compile-time type checking. * Common Lisp is for imperative, object-oriented programming. * Common Lisp is too specialized, it’s not for general-purpose development. * Common Lisp applications are hard to deploy. "
- slifin 7y agoIf you're interested in lisps and python's ecosystem you might enjoy lib python from Clojure: http://gigasquidsoftware.com/blog/2020/01/24/clojure-interop-with-python-nlp-libraries/ http://gigasquidsoftware.com/blog/2020/01/24/clojure-interop... https://run.nextjournalusercontent.com/kommen/parens-for-polyglot https://run.nextjournalusercontent.com/kommen/parens-for-pol...
- tom-thistime 7y agoThanks! Nothing would be more awesome than Lisp (or Scheme, I don't care) with easy transparent access to modern libraries.
- agumonkey 7y agoI wonder if someone made an invert hylang.. a python->clojure transpiler
- deleted 7y ago[deleted]
- phoe-krk 7y agoThese four things are common myths. It says so in the very line above them. This article is literally about debunking these myths.
- tsm 7y agoI learned Common Lisp in high school over a decade ago and have been passively looking for a CL job that doesn't require relocation since. This has been hard (though I did land a few Clojure gigs). Is anyone aware of active Lisp shops?
- vindarel 7y agoOn tools: note that the popular Atom editor has a great extension for interactive CL development, SLIMA, which has all the important features from Slime. We can also use CL in Jupyter notebooks, see those good examples: https://gist.github.com/WetHat/a49e6f2140b401a190d45d31e052af8f https://gist.github.com/WetHat/a49e6f2140b401a190d45d31e052a... And Vim, Lem, cl-repl, Eclipse (not so interactive)… https://lispcookbook.github.io/cl-cookbook/editor-support.html https://lispcookbook.github.io/cl-cookbook/editor-support.ht...
- mumblemumble 7y agoAssuming that the subtext here is wanting to address potential reasons for Lisp's chronic underpopularity, I think that all conversations like this miss the mark. Lisp was never failing to attract many users because people hadn't experienced sufficient evangelism about all its advanced features. It fails to attract many people because it's not a fun language to get started in. A year or so back I picked up a copy of Land of Lisp and burned through it for pleasure reading. And I was struck by how gross Lisp looks in that beginner-oriented treatment. Just this huge slog of car and cdr and let/letrec/let* and the 37 flavors of equals and the function namespace. . . and, all the while, you're being told that persevering in mastering this confusing minefield of subtleties will somehow enable you to write bug-free software. I doubt it's actually fun for most people, and the grandiose claims should beggar belief for everyone. I suppose I should count myself fortunate that I got to learn Lisp in college, where there was little attempt to make it fun, and plenty of graded assignments to keep me motivated. Racket and Clojure are right to clean up some of the language's evolutionary history. That's a start. But even then, the treatment in beginner's guides isn't all that enticing. I've also skimmed through Realm of Racket and Clojure for the Brave and True, and, while both of them work hard at being entertaining (and were fun to just sit and read), they don't really succeed at dispelling the sensation that what you're mostly doing is wrangling with the language itself. Compare with some of the more popular Python guides. They tend to be much more dryly written, but the actual flow of the guide tends to get you pretty quickly to from pypi import have_fun have_fun()
- abrax3141 7y agoFirst off, Lisp is chronically POPULAR not unpopular. (It is critically unpopular.) Secondly, Lisp is the most fun you can have programming, yeah from the start. You apparently had either a very poor teacher, or taught yourself Lisp ... same thing.
- kick 7y agoThe above post didn't say unpopular, they said 'underpopular'. While that's a bit of a neologism, it just implies that it's less popular than it should be. Also: "Lisp is the most fun you can have programming, yeah from the start," while subjective, is by most accounts, wrong. Especially when referring to Common Lisp; there could hardly be a more convoluted Lisp than Common Lisp.
- patrec 7y agoI hate the "lists of myths" (that aren't) genre. > Common Lisp does not have compile-time type checking. Nothing in the standard mentions compile time checking requirements and there is no useful de-facto standard that you (or tooling!) could seriously build upon either. I'd be suprised if python did not have better "compile-time type checking" for all practical purposes. Yes, SBCL gives much better type warnings at compile time than python, but for python you have mypy and it's A Thing, and still a joke compared to a proper type system like Ocaml's. > Common Lisp is too specialized, it’s not for general-purpose development. Common Lisp has no eco-system to speak of for machine learning, web development, command-line utilities, games programming, mobile development, GUI programming, embedded development or pretty much anything real general purpose languages do. If you have something for which Common Lisp is a good fit, you can still be commercially successful using it because not everything requires a super rich eco-system and for some problems what Common Lisp has is in fact highly competitive. But if you want to use common lisp effectively you definitely need to pre-select the problems you want to work on accordingly to an extent that's not true of python, C, C++, Rust, javascript, Go, Java, and half a dozen other languages. > Common Lisp applications are hard to deploy. No server or desktop or web-browser comes with common lisp pre-installed. Building common lisp is a pain, because packaging/ASDF is terrible and you don't easily get a nice and small statically linked executable out either. Compared to exactly what language is common lisp not hard to deploy?
- michaelanckaert 7y ago>> Common Lisp applications are hard to deploy. >No server or desktop or web-browser comes with common lisp pre-installed. Building common lisp is a pain, because packaging/ASDF is terrible and you don't easily get a nice and small statically linked executable out either. Compared to exactly what language is common lisp not hard to deploy? I'm not here to defend all of the flaws in CL, but I really enjoy the SBCL feature that allows you to compile to a binary. Yes it may not be as small as a pure C/C++/Rust executable, but it's very useful and I've used in various projects with great success. My heart still goes out to Python but I was I could just as easily create a Python executable as I can with SBCL.
- 7y ago
- tombert 7y agoI really need to learn CL one of these days; I know Clojure reasonably well, and enough Lisp-Flavour-Erlang, Chicken Scheme, and Racket to be dangerous, but for some reason I seem to have completely avoided CL. Based on the blog posts I've read, it seems like CL occupies the kind of space I want to be in: sort of the halfway point between theoretical and engineering. Is that a fair conclusion to draw?
- reikonomusha 7y agoIt’s a practical language that sometimes chooses less elegant ways to do things in favor of a complete, robust engineering experience. For instance, the fact defined functions sit in a different namespace than values creates mostly aesthetic ugliness where named functions and named values have different treatments. (defun f (x) (* x x)) (setq g (compose f f)) (g 5) This is wrong in Common Lisp on many levels: f must be referred to as #'f, and g cannot be called as such, you must use funcall: (funcall g 5) These might go against the sensibilities one might have had in learning a Lisp in the first place. But in practice, these don’t stop you from writing solid, readable code. It won’t feel as “clean” or “academic” as Scheme, but you’ll feel it easier to build large and efficient programs without pulling your hair out.
- jacobwilliamroy 7y agoI like it. But the really nice thing about lisp is if there's something I dont like, I can just hack the evaluator to fix it.
- dreamcompiler 7y agoIf I were doing the above a lot, I'd write compose as a macro (or better yet a compiler macro). In that case, the only thing above that needs to be changed is the setq, which would have to be written as (setf (fdefinition g) (compose f f)) Still different from Scheme, but some of the differences can be papered over with macros.
- kazinator 7y agoProgramming with a lot of higher order functions won't feel as clean in Common Lisp due to the #' and funcall. Basic Lisp programming with lists is a lot cleaner in a Lisp in which the empty list is false, and in which accessing nonexistent parts of a list (including the empty list) is a safe no-op that yields nil. Ashwin Ram's (cdr (assq key a-list)) almost works in Common Lisp in the form of (cdr (assoc key a-list)). See: https://ashwinram.org/1986/01/28/a-short-ballad-dedicated-to-the-growth-of-programs/ https://ashwinram.org/1986/01/28/a-short-ballad-dedicated-to... Imperative programming is better supported in Common Lisp because the evaluation of the arguments of most forms, including function calls, is ordered, mainly left to right, so side effect embedded in expressions will show stable, portable behavior. Scheme function calls have unspecified evaluation order, much like C. (In Common Lisp, the only unspecified aspect is whether the function cell is sampled before the arguments are evaluated, or just before the function is called. It's extremely rare for the arguments of a function call to be redefining the function cell, needless to say.) Common Lisp forms return a predictable value. If it doesn't make sense for a form to return a value, its value is not "undefined", but either just nil or else "no values". When a value returns no values, and an attempt is made to use its value anyway, then nil is produced as the value. You will not see some annoying #<undefined> in a Lisp REPL coming from a procedural construct.
- fmakunbound 7y agoCommon Lisp is still the most fun language to use for me. Sadly lacking in all the currently fashionable languages is interactivity.
- lincpa 7y agoLisp(Clojure) best practices: The Pure Function Pipeline Data Flow with Warehouse/Workshop Model https://github.com/linpengcheng/PurefunctionPipelineDataflow https://github.com/linpengcheng/PurefunctionPipelineDataflow
- 0xcde4c3db 7y ago> The myth: Common Lisp scripts and binaries are hard to distribute; binaries are too big. As far as I can tell, it's more like you have to pick one or the other. Distribution is easy if you don't mind distributing a 50 MB image (which is, of course, trivial for some applications and catastrophic for others). Most of the suggestions on reducing application size are essentially accounting sleight-of-hand that doesn't actually reduce the overall footprint (I'm reminded of the compressor that can "compress" any file by one byte... by moving the byte to the file name).