Note: this was originally a comment I wrote on
Lemmy in answer to the question “what
type of problems do you solve using Lisp?”. The post got to be a bit too
long, and I am re-publishing it here as a proper blog post. I am also
including some of a post I wrote on
Mastodon which
touched on some of these same issues.
So to answer the question: I have known about Common Lisp and Scheme for
years, but only recently started using them. This is the story of the 3
Lisp dialects that I use.
Emacs Lisp
I use Emacs and Emacs Lisp to manage my tens of thousands of text files,
I write Emacs Lisp scripts to automate simple tasks like searching for
pieces of information, formatting it, and outputting it to a report that
I might publish on my blog or send in an e-mail. I also use Emacs to
help with data cleaning before running machine learning processes. Emacs
helps with navigating CSV and JSON files, it also is a really good
batch file
renamer.
Scheme
I have recently started using Guile
Scheme to do some personal
projects. I went with Guile over the myriad other Scheme dialects
because it is the implementation used for the Guix package
manager and operating system.
-
Also, there the Goblins,
which is a distributed object-capability programming
system is
officially supported on the Guile platform, and I have been really
wanting to write applications using this programming style ever
since I first learned about it.
-
Also, there is the G-Golf
foreign interface layer allows Guile to automatically use an C
library that implements the GObject Introspection interface. So
through Guile, like with Python, you can use any C code library used
to create of all native apps in the Gnome,
MATE,
Cinnamon, or (my personal
favorite) the Xfce desktop environments. This
potentially makes Guile a viable alternative to Python scripting
across all of those Linux desktop environments.
Of all the Lisp dialects, Scheme is my favorite, for a few reasons:
-
It is absolutely tiny. Guile is relatively large (not as big as
Common Lisp), but other implementations are unbelievably small. for
example the Chez Scheme “petite” interpreter is fully compliant with
the R5RS standard, and the executable is like 308 kilobytes on a
64-bit Linux computer system.
-
Hygienic macros with
syntax-case
-
Recursive
functions
over using the loop
macro
of Common Lisp. When writing algorithms, I personally find it easier
to reason about recursive functions than loops. Scheme also provides
me the ease-of-mind that comes with knowing the optimizing Scheme
compiler will ensure recursive loops will never overflow the stack.
-
Pattern
matching
is well supported by most Scheme implementation.
-
It is a "Lisp-1" system, meaning there is only one namespaces
for variables and functions, as opposed to Common Lisp (a "Lisp-2
system") which allows a name to be either a variable, a function, or
both. I personally find it easier to reason about higher-order
functions
in Lisp-1 systems.
-
Support for Delimited
Continuations,
which is a fairly recent discovery of computer language theory
(first being discussed back in the 1990s), but is available across a
few Scheme implementations.
Common Lisp
That said, I am also starting experimenting with Embedded Common Lisp
(ECL) because it is a lightweight
standards compliant Common Lisp implementation that compile your program
into C++ code, and this is useful to my professional work.
The modern software industry, especially in the realm of big data and
machine learning, has mostly settled on a pattern of using C++ for
creating performance critical libraries, and creating Python binding to
the C++ libraries for scripting. I was hoping languages like Haskell
and/or Rust might come along and change all this, but it will take
decades (if ever) for the software industry to turn in that direction.
The problem with Python, in my experience (and I believe many other
software engineers would agree) is that it does not scale well to larger
applications at all, whereas Common Lisp does. This is for various
reasons, but mostly due to how Lisp does strong dynamic typing, and also
the CLOS implementation of the meta-object protocol. Yet too many
companies waste time writing large applications in Python — applications
that are much larger than the scripting use cases that Python was
originally intended to be used. I believe this is time and money better
spent on other things.
So I see Common Lisp, and the ECL compiler, as a potentially viable
alternative to the sub-optimal status quo of Python as a scripting layer
around C++ code libraries, at least perhaps for my day job, if not being
more generally true industry-wide. Mostly, ECL would allow me to write a
program in Common Lisp instead of Python, but deliver to my clients the
C++ code that ECL generates to be used in their machine learning
projects. (I have not actually done this yet, I am still investigating
whether this would be a viable solution to any of my projects).
ECL makes it easy to use C++ libraries through Lisp instead of Python.
And there are so many good C++ libraries out there:
Qt, OpenCV,
Tensorflow,
PyTorch,
OpenSceneGraph,
FreeCAD, Godot game
engine, Blender.
And it compiles easily on Linux/Unix (GCC), Windows (MSVC), and MacOS
(via Clang++), so good for cross-platform development.
Conclusions
So in spite of Lisp being such an old family of languages (its earliest
incarnations dating all the way back to 1958), and being superseded in
popularity and widespread use by languages like Python and JavaScript
across the software industry, Lisp is still a modern, relevant,
evolving, and very useful family of programming languages. At the same
time, a Lisp such as Scheme or Common Lisp would even be a better choice
of programming language in many applications where Python is currently
used.
I just hope I eventually find the time to try out all of these Common
Lisp and Scheme related ideas I have. I especially hope ECL turns out to
be a profitable technological choice for the professional work that I
do. But only time will tell.
Please feel free to comment here, or on Mastodon