<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Elia Scotto</title><description>Latest tech articles</description><link>https://scotto.me/</link><item><title>Shai-Hulud and the risks of external dependencies</title><link>https://scotto.me/blog/2026-07-29-shai-hulud-code-review/</link><guid isPermaLink="true">https://scotto.me/blog/2026-07-29-shai-hulud-code-review/</guid><description>Shai-Hulud code review</description><pubDate>Wed, 29 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://www.akamai.com/blog/security-research/mini-shai-hulud-worm-returns-goes-public&quot;&gt;Shai-Hulud&lt;/a&gt; is a malware created by TeamPCP that targeted &lt;em&gt;npm&lt;/em&gt; to spread across the Node supply chain. Its name refers the giant &lt;a href=&quot;https://en.wikipedia.org/wiki/Sandworm_(Dune)&quot;&gt;sandworms&lt;/a&gt; that populate the desert planet Arrakis in the sci-fi series &lt;em&gt;Dune&lt;/em&gt; by &lt;a href=&quot;https://en.wikipedia.org/wiki/Frank_Herbert&quot;&gt;Frank Herbert&lt;/a&gt;. If you&amp;#39;ve seen the movie, they are the creatures that get attracted by vibrations in the sand. The reference is explained clearly in the README:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A sandworm surfaces in the desert. It takes everything.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;An estimate of the damage caused by Shai-Hulud through multiple campaigns includes 500 compromised software packages, hundreds of organisations breached, 300 GB of data stolen, and roughly 500,000 credentials exfiltrated to the attackers.&lt;/p&gt;
&lt;p&gt;TeamPCP decided to release its source code on 11 May. I’m not a security researcher, but I’ve always been interested in how criminals exploit complex systems and bypass their security. So I forked the repo to see what intrusion techniques or exploits were used. I also took some notes to turn into a code review article later. But the more I read through the code, the more I felt somehow disappointed.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/img/Shai-Hulud_restricted_mode.png&quot; alt=&quot;&quot; title=&quot;Reading Shai-Hulud code&quot;&gt;&lt;/p&gt;
&lt;p&gt;I didn&amp;#39;t find any advanced exploit system, but rather a collection of simple tricks to steal credentials, obfuscate strings, and inject malicious code into npm packages. At times, the code was inconsistent, contained a few bugs, and appeared incomplete.&lt;/p&gt;
&lt;p&gt;So how did a codebase like this become so harmful? Because it exploited the Achilles&amp;#39; heel in modern development. The trust we place in other people&amp;#39;s code and how much we love dependencies.&lt;/p&gt;
&lt;h2&gt;How it works&lt;/h2&gt;
&lt;p&gt;The codebase I’ve analysed is Mini Shai-Hulud. There have been three versions of the worm, with what appears to be an increasing number of features from one version to another.&lt;/p&gt;
&lt;p&gt;The project uses &lt;em&gt;Bun&lt;/em&gt; for its build process, and the README includes it&amp;#39;s usage instructions. &lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Drop this into a CI pipeline. The sandworm crawls through your infrastructure, feeding on credentials from every provider it can reach, then exfiltrates through encrypted channels. If it finds npm tokens or OIDC access, it backdoors packages and publishes them. Downstream consumers install the infection. The worm grows.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Preflight and infection&lt;/h3&gt;
&lt;p&gt;Once the worm starts running, it first performs some checks, becomes a daemon if it is not running inside a CI environment, and compromises the &lt;a href=&quot;https://www.npmjs.com/package/@opensearch-project/opensearch&quot;&gt;OpenSearch&lt;/a&gt; repository if the infected system has access to it, using an OIDC attack.&lt;/p&gt;
&lt;p&gt;The worm uses two separate methods to poison a package. The OIDC attack involves injecting a new optional dependency, &lt;code&gt;@opensearch/setup&lt;/code&gt;, pinned to a specific commit in another package, &lt;code&gt;opensearch-project/opensearch-js&lt;/code&gt;, which has presumably already been compromised. The other method adds a &lt;code&gt;preinstall&lt;/code&gt; script containing a malicious setup file that downloads Bun and then runs the worm.&lt;/p&gt;
&lt;h3&gt;Credentials harvesting&lt;/h3&gt;
&lt;p&gt;Because the code has access to the host system, it simply reads configuration files and grabs tokens from processes and apps.&lt;/p&gt;
&lt;p&gt;In short, it steals almost everything a developer can access: AWS credentials and secrets, SSH keys, cloud configuration files, cryptocurrency wallets, web chat data, VPN configurations, Kubernetes credentials, HashiCorp Vault secrets, GitHub tokens, Actions secrets, Claude settings, &lt;code&gt;.npmrc&lt;/code&gt;, &lt;code&gt;.netrc&lt;/code&gt;, Bash, Zsh, and Python shell histories, and MySQL, PostgreSQL, and Redis credentials.&lt;/p&gt;
&lt;h3&gt;Data exfiltration&lt;/h3&gt;
&lt;p&gt;Once the malware has collected the credentials, it needs to send them to the attackers. The data is first compressed and encrypted using a public key embedded in the payload.&lt;/p&gt;
&lt;p&gt;The malware then tries to contact the typosquatted domain &lt;code&gt;git-tanstack.com&lt;/code&gt;. If that fails, it searches GitHub for other compromised repositories through signed commit messages and retrieves a fallback domain from one of them. If even that fails, it creates multiple GitHub repositories with names made from random adjectives and nouns drawn from &lt;em&gt;Dune&lt;/em&gt;. The stolen data is later uploaded to these repositories through a GitHub Actions workflow.&lt;/p&gt;
&lt;p&gt;A quick GitHub search showed thousands of repositories containing encrypted JSON data. A significant number of these repositories were created only a few days after the release of Mini Shai-Hulud’s source code, making me wonder whether someone had used it in a new campaign.&lt;/p&gt;
&lt;h3&gt;Embedded payload&lt;/h3&gt;
&lt;p&gt;The payload contains a few scripts that download and install Bun on the system before executing the malware. Two of the files are configuration files for VS Code and Claude, designed to be injected into repositories so that whenever a user opens the project in the editor or with a coding agent, the worm compromises the machine and replicates itself. There is also a GitHub Actions workflow designed to collect repository secrets and upload them as artifacts. Then there are two public keys: one used to encrypt data and another to verify commit signatures. Finally, there is a Python script that dumps the memory of a GitHub Actions runner.&lt;/p&gt;
&lt;p&gt;The payload contains also the &lt;code&gt;DEADMAN_SWITCH&lt;/code&gt;, a Bash script that installs a daemon that once minute for the next 24h checks whether the GitHub token has been revoked, and if it has, wipes the home directory.&lt;/p&gt;
&lt;h3&gt;Obfuscation&lt;/h3&gt;
&lt;p&gt;The code is obfuscated at build time in two layers. The first makes important strings unreadable in the built code and decodes them only at runtime. This prevents a signature-based malware detector from being triggered by a string such as &lt;code&gt;rm -rf ~&lt;/code&gt;, because it is transformed into something like &lt;code&gt;LG+0RPNiAq6wTcBsei6MwLKLjyZ79e67&lt;/code&gt;. The second layer obfuscates the entire codebase with &lt;code&gt;javascript-obfuscator&lt;/code&gt; library.&lt;/p&gt;
&lt;h2&gt;Imperfect code&lt;/h2&gt;
&lt;p&gt;I found a few issues in the codebase. Some expected files are missing, which could potentially prevent execution of a part of the malware. The bootstrapper exits if Bun is already installed, without executing the worm. &lt;code&gt;BASH_LOADER&lt;/code&gt; and &lt;code&gt;PYTHON_LOADER&lt;/code&gt; appear unused. The fallback-domain verification mechanism uses mismatched markers: it searches for &lt;code&gt;thebeautifulmarchoftime&lt;/code&gt; but parses &lt;code&gt;thebeautifulsnadsoftime&lt;/code&gt;, so verification with &lt;code&gt;verify_key.pub&lt;/code&gt; likely never succeeds. I also found unused TypeScript interfaces and some &lt;code&gt;catch&lt;/code&gt; and &lt;code&gt;finally&lt;/code&gt; blocks left empty.&lt;/p&gt;
&lt;p&gt;The credentials stealing and the &lt;code&gt;DEADMAN_SWITCH&lt;/code&gt; script targets macOS and Linux systems. Code targeting Windows appears in the codebase, but it&amp;#39;s unused. A good amount of Node developers use macOS, while CI systems usually run Linux, so if those were the main targets, maybe there was little reason to support Windows.&lt;/p&gt;
&lt;p&gt;The README claims that the malware was vibe-coded, but it made me wonder whether an agent could have quickly fixed a few of these issues. The the source contains signs of work produced across multiple prompts: inconsistent abstractions, unfinished branches, unused interfaces, and code that appears to have been patched together from few sources, or precedent versions. The author seems fairly knowledgeable about security and build pipelines, but the project has been left in a prototype state.&lt;/p&gt;
&lt;p&gt;The important lesson from this codebase it that it doesn’t have to be particularly sophisticated or complex to exploit a supply chain.&lt;/p&gt;
&lt;h2&gt;How this happened?&lt;/h2&gt;
&lt;p&gt;What we have ignored for years is that every time we run &lt;code&gt;npm install&lt;/code&gt;, we give code written by others access to our machine and the network. It sounds nightmarish, but that’s what happens.&lt;/p&gt;
&lt;p&gt;Every time you run a linter, whether directly or through your editor, compromised code can steal your credentials, access your servers and cryptocurrency wallets, send your data to a remote server, and push new versions of your repositories to GitHub with poisoned dependencies, spreading itself like a worm. Dependencies are insecure, and editor extensions are no exception[^1].&lt;/p&gt;
&lt;p&gt;Node, the runtime behind most JavaScript projects, has security flaws built into its design, as its creator, Ryan Dahl, &lt;a href=&quot;https://www.youtube.com/watch?v=M3BM9TB-8yA&amp;t=362s&quot;&gt;has himself acknowledged&lt;/a&gt;. We got used to writing web applications faster by relying on a large number of dependencies and on a network of trust, expecting maintainers and the open-source community to do a good job. Very large companies were built using these technologies.&lt;/p&gt;
&lt;p&gt;While forward-thinking companies developed the habit of giving back to the community by open-sourcing their code and financially supporting maintainers, we also saw &lt;a href=&quot;https://www.zdnet.com/article/when-open-source-developers-go-bad/&quot;&gt;signs&lt;/a&gt; that this equilibrium was not always stable.&lt;/p&gt;
&lt;p&gt;TeamPCP decided to attack developers because, in some respects, we became an easy target. Also the credentials on our machines are more valuable than ordinary users’ data. Now that writing imperfect but runnable code has become extremely cheap thanks coding agents, we should stop blindly trusting third-party code without security measures in place.&lt;/p&gt;
&lt;h2&gt;What can we do?&lt;/h2&gt;
&lt;p&gt;The creator of Odin, Ginger Bill, argued last year that &lt;a href=&quot;https://www.gingerbill.org/article/2025/09/08/package-managers-are-evil/&quot;&gt;package managers are evil&lt;/a&gt;. I recommend reading the article because it’s very interesting. The key point for this discussion is that we tend to trust others and therefore “assume random code off the internet &lt;em&gt;works&lt;/em&gt;”.&lt;/p&gt;
&lt;p&gt;We have become used to believing that code published online is reliable, and that relying on third-party packages whenever possible is efficient[^2]. We hid the &lt;a href=&quot;https://en.wikipedia.org/wiki/Dependency_hell&quot;&gt;dependency hell&lt;/a&gt; behind automated systems, making it nice and easy to use, but almost impossible to verify what code we are actually importing. If a dependency nested four layers down gets compromised, developers will install and run it, without even realising what happened.&lt;/p&gt;
&lt;p&gt;Token protection, credential rotation, CI monitoring, delayed dependency updates, agentic auditing and supervision can reduce the risk, but they do not remove the design problem. Node, Python, Rust, Ruby and Go all rely on third-party dependencies whose code execute with the same privileges as the application, without being isolated from the rest of the system.&lt;/p&gt;
&lt;p&gt;Going forward, we should seriously consider adopting a &lt;strong&gt;zero-trust mindset&lt;/strong&gt; when developing software.&lt;/p&gt;
&lt;p&gt;npm has &lt;a href=&quot;https://github.blog/changelog/2026-06-09-upcoming-breaking-changes-for-npm-v12/&quot;&gt;recently removed&lt;/a&gt; the ability for packages to run their own scripts during installation. As a result, it will no longer execute &lt;code&gt;preinstall&lt;/code&gt;, &lt;code&gt;install&lt;/code&gt;, or &lt;code&gt;postinstall&lt;/code&gt; scripts from dependencies, which helped previous versions of Shai-Hulud spread.&lt;/p&gt;
&lt;p&gt;One effective approach often proposed online is to &lt;strong&gt;reduce the number of dependencies to a minimum&lt;/strong&gt;. Prefer mature, &lt;strong&gt;actively maintained packages&lt;/strong&gt; with a &lt;strong&gt;limited dependency tree&lt;/strong&gt; and a long, stable release history. This would reduce the probability of being attacked through small, obscure dependencies.&lt;/p&gt;
&lt;p&gt;Also we can consider choosing programming languages that provide &lt;strong&gt;larger standard libraries&lt;/strong&gt; and runtimes, so we can write code faster without the need to import many external packages.&lt;/p&gt;
&lt;p&gt;When dependencies are necessary, they can be distributed with a reliable &lt;strong&gt;release model&lt;/strong&gt; closer to those used by linux distributions like Debian, with different channels such as &lt;code&gt;stable&lt;/code&gt;, &lt;code&gt;testing&lt;/code&gt;, and &lt;code&gt;nightly&lt;/code&gt;. This would allow code to be audited by a larger community of maintainers, preventing frequent release.&lt;/p&gt;
&lt;p&gt;A stronger protection comes from &lt;strong&gt;limiting access to third-party code&lt;/strong&gt;. This has been successfully applied by Apple in macOS, by requiring permission before they can access sensitive folders or other apps’ data.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/img/macos_access_allow.png&quot; alt=&quot;Adobe Photoshop 2025 macOS access screen&quot; title=&quot;You wouldn&amp;#39;t give Photoshop 2025 access to your data, right?&quot;&gt;&lt;/p&gt;
&lt;p&gt;A more effective approach is to &lt;strong&gt;sandbox third-party dependencies&lt;/strong&gt;. The code runs inside an isolated and restricted environment, preventing it from compromising the system.&lt;/p&gt;
&lt;p&gt;These techniques have been partially addressed by the new JavaScript runtime &lt;a href=&quot;https://deno.com/&quot;&gt;Deno&lt;/a&gt;, another project created by Node creator Ryan Dahl. Deno implements runtime permissions and package sandboxing. It provides dependency auditing, minimum-age controls, a larger built-in toolset, and it&amp;#39;s almost entirely compatible with npm packages. It does not eliminate the problem of trusting external dependencies, but it reduces the amount of permissions granted to them by default.&lt;/p&gt;
&lt;p&gt;Whatever we choose, we should start considering every single dependency as a new tradeoff. We need to become responsible for it, rather than expecting someone else to take that responsibility.&lt;/p&gt;
&lt;p&gt;[^1]: One of the latest attack from TeamPCP in May, involved a GitHub developer installing a malicious software extension for VSCode, which ended up in almost 4000 private repositories violated.
[^2]: &lt;a href=&quot;https://www.npmjs.com/package/is-string&quot;&gt;is-string&lt;/a&gt; has 83K weekly download.&lt;/p&gt;
</content:encoded></item><item><title>A Road to Lisp: Which Lisp</title><link>https://scotto.me/blog/2026-07-17-which-lisp/</link><guid isPermaLink="true">https://scotto.me/blog/2026-07-17-which-lisp/</guid><description>Comparison of modern Lisp dialects</description><pubDate>Fri, 17 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Most programming languages evolve as a single language. Python, Java, Javascript, C++, have new versions and standards, multiple implementations, but they still remain the same language. C and C++ can be compiled with GCC or Clang, Python can be compiled with CPython or PyPy, the same JavaScript runs in both Firefox and Chrome, and Java programs can run on JVM or GraalVM.&lt;/p&gt;
&lt;p&gt;Lisp is not like that.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/img/lisp-logo.svg&quot; alt=&quot;[Lisp Logo]&quot; title=&quot;Lisp logo, NASA version.&quot;&gt;&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://en.wikipedia.org/wiki/Lisp_(programming_language)&quot;&gt;Wikipedia&lt;/a&gt; page lists more than 20 different &lt;em&gt;dialects&lt;/em&gt;, which means there are many variations to choose from. That’s because &lt;strong&gt;Lisp is a &lt;em&gt;family&lt;/em&gt; of programming languages&lt;/strong&gt;. They share the same fundamental syntax but differ in their operators, semantics, standard libraries, and language capabilities.&lt;/p&gt;
&lt;p&gt;One of the main concerns Lisp beginners have is which dialect to learn first. I see this question frequently asked in online forums. The answer is that the dialect matters, but not as much as a beginner might think. Learning Lisp is about learning a new type of programming. &lt;strong&gt;A new way of thinking about problems using code.&lt;/strong&gt; You will learn the fundamental concepts with any dialect. Then, once you have learned one, it will be relatively easy to switch to another.&lt;/p&gt;
&lt;p&gt;I will briefly present the most relevant dialects that are actively used and maintained. I’ll try to highlight their strengths and weaknesses to help you overcome your indecision and pick one to start your Lisp journey. &lt;/p&gt;
&lt;p&gt;If you are a beginner, many of the concepts in this article might be completely new to you. Don’t worry too much about them yet. When I was a beginner, I found many of these concepts fascinating and they pushed me to learn more about the Lisp world.&lt;/p&gt;
&lt;h2&gt;Common Lisp&lt;/h2&gt;
&lt;p&gt;Abbreviated as CL, it is the most mature and comprehensive of all Lisp dialects. It’s considered the old-school Lisp, since the language — I will call it a &lt;em&gt;language&lt;/em&gt; from now on — was standardised in 1994 with a formal ANSI specification. Thanks to this standardisation, there are multiple implementations of Common Lisp targeting different platforms and use cases.&lt;/p&gt;
&lt;p&gt;The most famous implementation is &lt;em&gt;SBCL&lt;/em&gt;, which compiles directly to native code. It is fast, open-source, and compatible with modern hardware. With it, well-written Common Lisp code can achieve performance comparable to C and Rust. Because SBCL optimises heavily, it compiles a bit more slowly than other implementations but generates some of the fastest code in the Lisp family.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/img/common-lisp-logo.svg&quot; alt=&quot;[Common Lisp Logo]&quot; title=&quot;The Yin and Yang Common Lisp logo. The lambda symbol (λ) refer to lambda calculus invented by Alonzo Church.&quot;&gt;&lt;/p&gt;
&lt;p&gt;When I said above that Common Lisp is the most comprehensive dialect, I meant that it offers the broadest set of features among all Lisps. It provides a large amount of functionality out of the box, much of it defined directly in the standard. For example, CL has functions for controlling compilation and evaluation from within the language itself (&lt;code&gt;COMPILE&lt;/code&gt;, &lt;code&gt;LOAD&lt;/code&gt;, &lt;code&gt;EVAL&lt;/code&gt;, &lt;code&gt;COMPILE-FILE&lt;/code&gt;, and others). This means that I can use these functions in my code or at the REPL to tell the Lisp process to compile a function, load a file, or evaluate some code. CL also provides &lt;code&gt;DISASSEMBLE&lt;/code&gt;, which lets you inspect the machine code generated for a compiled function.&lt;/p&gt;
&lt;p&gt;Common Lisp has a condition and restart system, which is one of the most powerful way I ever saw to debug and inspect programs. If a condition occurs during execution, the Lisp process might stop and let you inspect the state of the program and its variables at that point in time. You can then choose to restart the program and maybe retry the operation, or ignore the condition and continue execution. This is also possible because the Common Lisp REPL is deeply integrated with the running system. If your program fails on a remote server, you can connect to its REPL and inspect the live process to understand what went wrong.&lt;/p&gt;
&lt;p&gt;Common Lisp supports all major programming paradigms, like functional, imperative, metaprogramming, and object-oriented programming. It offers one of the most advanced object systems, called &lt;a href=&quot;https://courses.cs.northwestern.edu/325/readings/clos.html&quot;&gt;CLOS&lt;/a&gt;, which supports features such as multiple dispatch and generic functions. This makes OOP more flexible than in common object-oriented languages such as Java or C++. It is also worth noting that Common Lisp is dynamically typed but has a rich and expressive type system with optional type declarations.&lt;/p&gt;
&lt;p&gt;Standardisation means that the language is stable. The ANSI Common Lisp from 1994 is still the one in use today. Because of it, lispers rarely fall victim to &lt;em&gt;backward incompatibility&lt;/em&gt;, and old Common Lisp code often still runs perfectly today. For example, if you go through old Lisp books such as &lt;a href=&quot;https://github.com/norvig/paip-lisp&quot;&gt;PAIP&lt;/a&gt; by Peter Norvig, published in 1991, you’ll find that much of the code still runs on modern implementations. With Common Lisp, you encounter far fewer of the incompatibilities typical of languages like Ruby and Python. Even Common Lisp libraries that haven’t been updated recently will often still run fine on your system because they don’t need to be continually adapted to new versions of the language.&lt;/p&gt;
&lt;p&gt;Common Lisp lacks some conveniences that have become common in newer languages, such as concise literals for a wider variety of data structures, persistent immutable collections, lazy sequences and built-in general-purpose pattern matching. Common Lisp was designed in the 1980s by consolidating several existing Lisp dialects into a single language. Its designers chose to retain much of the syntax and patterns of those older dialects, making sure that existing Lisp programmers could adopt the language without having to learn a completely new syntax.&lt;/p&gt;
&lt;p&gt;Common Lisp doesn’t have a central direction or corporate sponsor. The community is relatively small and spread across several implementations, projects and communication channels. It’s mostly made up of volunteers who help keep the language alive. It can be a bit difficult to find guides and help: tutorials are often either too simple or too advanced, and documentation is not always easy to find.&lt;/p&gt;
&lt;p&gt;It’s currently used in &lt;a href=&quot;https://www.youtube.com/watch?v=svmPz5oxMlI&quot;&gt;quantum computing&lt;/a&gt; at &lt;a href=&quot;https://www.rigetti.com/&quot;&gt;Rigetti Computing&lt;/a&gt;, and has been used at &lt;a href=&quot;https://www.grammarly.com/blog/engineering/running-lisp-in-production/&quot;&gt;Grammarly&lt;/a&gt; for its core grammar service and also powers &lt;a href=&quot;https://www.itasoftware.com/&quot;&gt;Google Flight Search&lt;/a&gt;. Worth mentioning is &lt;a href=&quot;https://codeberg.org/shirakumo/kandria&quot;&gt;Kandria&lt;/a&gt;, an open-source video game released on Steam and written entirely in Common Lisp. &lt;/p&gt;
&lt;p&gt;An interesting fact: Paul Graham originally wrote HackerNews in a custom Lisp dialect called Arc, based on Racket. Today, Daniel Gackle (&lt;a href=&quot;https://news.ycombinator.com/user?id=dang&quot;&gt;@dang&lt;/a&gt;) reimplemented it in Clarc, a Common Lisp implementation of Arc that runs on SBCL&lt;a href=&quot;https://news.ycombinator.com/item?id=41683969&quot;&gt;^1&lt;/a&gt;, serving around 10 million pages per day.&lt;/p&gt;
&lt;h3&gt;Where Common Lisp shines&lt;/h3&gt;
&lt;p&gt;CL compiles to native code on all major operating systems and can achieve fast execution, at the cost of slightly slower startup times, so it’s great for long-running processes. It offers one of the most powerful REPLs among Lisp dialects and can be considered, despite its steep learning curve, one of the fastest languages for writing solid software in a short time.&lt;/p&gt;
&lt;p&gt;CL shines when you need to do research and prototyping with quick iterations, as in quantum computing, or when the specifications aren’t fully defined yet and change frequently, requiring the software to adapt quickly, as in startups. Paul Graham wrote a famous and inspiring &lt;a href=&quot;https://www.paulgraham.com/avg.html&quot;&gt;article&lt;/a&gt; about how Common Lisp helped his internet startup beat the competition.&lt;/p&gt;
&lt;h3&gt;Learning resources&lt;/h3&gt;
&lt;p&gt;A good starting point is &lt;a href=&quot;https://stevelosh.com/blog/2018/08/a-road-to-common-lisp/&quot;&gt;A Road to Common Lisp&lt;/a&gt; by Steve Losh, which inspired me to write this series. One of the most accessible books for beginners is &lt;a href=&quot;https://gigamonkeys.com/book/&quot;&gt;Practical Common Lisp&lt;/a&gt; by Peter Seibel, which is available entirely online. It’s the best introduction to the language I’ve read, as the most important concepts are neatly separated into chapters. A more playful introduction is &lt;a href=&quot;http://landoflisp.com/&quot;&gt;Land of Lisp&lt;/a&gt;, which uses funny characters and comics to teach programming through games. A more advanced book that I enjoyed is &lt;a href=&quot;https://www.paulgraham.com/onlisp.html&quot;&gt;On Lisp&lt;/a&gt; by Paul Graham, which is entirely dedicated to macros.&lt;/p&gt;
&lt;p&gt;The best IDE support for CL is Emacs + &lt;a href=&quot;https://github.com/joaotavora/sly&quot;&gt;Sly&lt;/a&gt;/&lt;a href=&quot;https://slime.common-lisp.dev/&quot;&gt;Slime&lt;/a&gt; (&lt;a href=&quot;https://github.com/doomemacs/doomemacs&quot;&gt;Doom&lt;/a&gt; already has support for it) or Vim + &lt;a href=&quot;https://github.com/vlime/vlime&quot;&gt;VLime&lt;/a&gt;. A weaker alternative is VSCode + &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=rheller.alive&quot;&gt;Alive&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;One of the best resources for beginners is &lt;a href=&quot;https://lispcookbook.github.io/cl-cookbook/&quot;&gt;The Common Lisp Cookbook&lt;/a&gt;, which has many up-to-date tutorials. For references and libraries, the &lt;a href=&quot;https://github.com/CodyReichert/awesome-cl&quot;&gt;Awesome-CL&lt;/a&gt; list is worth a look. I also printed my own copy of the &lt;a href=&quot;http://clqr.boundp.org/&quot;&gt;Common Lisp Quick Reference&lt;/a&gt; booklet, which can be faster than finding information in the CL &lt;a href=&quot;https://www.lispworks.com/documentation/HyperSpec/Front/index.htm&quot;&gt;HyperSpec&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Clojure&lt;/h2&gt;
&lt;p&gt;Rich Hickey created it during a sabbatical year, frustrated by clients refusing to let him use Common Lisp instead of Java and C# because they were concerned about compatibility and maintenance issues. So he decided to write a new Lisp language targeting the JVM, allowing it to access everything the Java ecosystem had built over decades and making it a practical language from the start. The deal is that Clojure provides the language, while the host platform — the JVM — provides the runtime.&lt;/p&gt;
&lt;p&gt;Clojure compiles directly to JVM bytecode, which means it’s compatible with any codebase that runs on the JVM (Java, Kotlin, Scala). This compatibility means that Clojure can coexist with other JVM languages in the same codebase, use Java libraries directly, and access all the features the JVM offers, such as OS portability, garbage collection, a fast and optimised runtime, and so on.&lt;/p&gt;
&lt;p&gt;Rich Hickey chose to target the JVM so that he didn&amp;#39;t have to reinvent the wheel and build a new compiler for Clojure from scratch. Instead, he focused his efforts on reading research papers on language design and data structures, bringing some of the newest and most effective ideas into the language.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/img/clojure-logo.svg&quot; alt=&quot;[Clojure Logo]&quot; title=&quot;The Clojure logo, designed by Tom Hickey, Rich&amp;#39;s brother.&quot;&gt;&lt;/p&gt;
&lt;p&gt;The language at its core is composed of &lt;strong&gt;pure functions operating on immutable data structures&lt;/strong&gt;. Instead of making mutable objects the primary way to represent changing state, it provides explicit mechanisms such as &lt;em&gt;atoms&lt;/em&gt;, &lt;em&gt;refs&lt;/em&gt; and &lt;em&gt;agents&lt;/em&gt; for managing change. This design choice makes Clojure a &lt;em&gt;functional&lt;/em&gt; programming language. It supports object-oriented programming, but replaces class-based inheritance with abstractions such as protocols and multimethods. Also the syntax is more modern than Common Lisp’s, with richer literals, destructuring, and overall more compact code.&lt;/p&gt;
&lt;p&gt;Clojure also comes with several new features. Its persistent data structures use structural sharing, making immutable updates efficient. It also uses lazy sequences, which allow computations to be performed only when their results are needed. It has strong support for concurrency through constructs such as &lt;em&gt;atoms&lt;/em&gt;, &lt;em&gt;refs&lt;/em&gt;, &lt;em&gt;agents&lt;/em&gt; and &lt;em&gt;futures&lt;/em&gt;, and provides &lt;em&gt;records&lt;/em&gt; and custom data types when more structured data is needed. &lt;a href=&quot;https://github.com/edn-format/edn&quot;&gt;EDN&lt;/a&gt; (Extensible Data Notation) offers a simple extensible data format based on Clojure’s literals, a better lispy alternative to JSON, YAML and similar. Clojure doesn&amp;#39;t have types, but &lt;code&gt;clojure.spec&lt;/code&gt; can be used to describe, validate and generate data without introducing a static type system, useful in large applications.&lt;/p&gt;
&lt;p&gt;Rich Hickey designed Clojure with the intention of prioritising stability, similar to what standardisation did for Common Lisp. Even though the language is actively developed, you don’t need to expect major deprecations when updating to a newer version, since the maintainers preserve backwards compatibility and mostly add new features through core libraries.&lt;/p&gt;
&lt;p&gt;Since Clojure is designed to be hosted on other platforms, it can be ported to other runtimes, like the JavaScript engine that runs in your browser. &lt;em&gt;ClojureScript&lt;/em&gt; is a Clojure compiler that targets JavaScript rather than the JVM, so the same language can run on both the server and the browser. This means that Clojure can be used as a full-stack language.&lt;/p&gt;
&lt;p&gt;The JVM integration is great, but it comes with some trade-offs. Error messages are contaminated with a lot of Java implementation details and aren’t always self-explanatory, so stack traces are not necessarily helpful when debugging issues. Java profilers like YourKit are compatible, but even there you will see a lot of Java classes, and it can be hard to map them back to the code you wrote.&lt;/p&gt;
&lt;p&gt;In general you don’t need to know Java to learn Clojure. I didn’t know Java when I started and never had substantial problems because of that. However, knowing how to tweak the JVM can be helpful when doing performance tuning on the server.&lt;/p&gt;
&lt;p&gt;The community around Clojure is small but active and happy to help newcomers pick up the language quickly. It’s known as &lt;em&gt;Clojurians&lt;/em&gt; and mostly hangs out on Slack, where you can also collaborate on open-source projects and find job opportunities.&lt;/p&gt;
&lt;p&gt;Clojure is actively used by companies and startups around the world, and it’s probably the most widely used Lisp in production. Some big names include Nubank (one of the largest fintech companies in Latin America), which acquired Cognitect (the main sponsor of Clojure’s development), as well as Walmart, Netflix, Apple, Salesforce, Amazon, Cisco, and Grammarly.&lt;/p&gt;
&lt;h3&gt;Where Clojure shines&lt;/h3&gt;
&lt;p&gt;Clojure shines in large software systems where the workload consists of a lot of data processing, or more broadly, anywhere you might previously have picked Java. Code can be written and tested quickly through continuous iteration thanks to the REPL, making the language suitable for delivering reliable solutions in less time. Its immutable design helps eliminate some of the hardest concurrency bugs, while its functional orientation guides programmers towards writing programs as a series of data transformations.&lt;/p&gt;
&lt;p&gt;Clojure is great in fields where operations need to happen quickly and often involve processing large sets of data, such as finance and trading. It’s also great for startups solving domain-specific problems with complex logic, since the language’s extensibility allows it to be modelled around the problem.&lt;/p&gt;
&lt;h3&gt;Learning resources&lt;/h3&gt;
&lt;p&gt;To give Clojure a try, you might want to check out &lt;a href=&quot;https://tryclojure.org/&quot;&gt;Try Clojure&lt;/a&gt;, then solve some exercises like the &lt;a href=&quot;http://clojurekoans.com/&quot;&gt;Clojure Koans&lt;/a&gt;, followed by &lt;a href=&quot;https://4clojure.oxal.org/&quot;&gt;4Clojure&lt;/a&gt; for more advanced stuff.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://clojure.org/index&quot;&gt;official website&lt;/a&gt; offers some of the most curated material you can find, with great explanations of all the core features and the motivations behind the design choices that make the language special. Clojure also has one of the best &lt;a href=&quot;https://clojuredocs.org/&quot;&gt;documentation&lt;/a&gt; websites I’ve ever found for a language. All the core library functions come with docstrings, and the community has added usage examples, so you can quickly grasp what each function does.&lt;/p&gt;
&lt;p&gt;The best &lt;em&gt;pitch&lt;/em&gt; for the language is &lt;a href=&quot;https://yogthos.net/ClojureDistilled.html&quot;&gt;Clojure Distilled&lt;/a&gt;. It’s probably one of the shortest explanations of what Clojure has to offer.&lt;/p&gt;
&lt;p&gt;After the release of Clojure, Rich Hickey became famous for a series of talks about software design, in which he shared his deep expertise in fundamental topics like simplicity in software design, state and time, databases, concurrency, and language design. Some of his best talks — &lt;a href=&quot;https://www.youtube.com/watch?v=SxdOUGdseq4&quot;&gt;&lt;em&gt;Simple Made Easy&lt;/em&gt;&lt;/a&gt;, &lt;a href=&quot;https://www.youtube.com/watch?v=-6BsiVyC1kM&quot;&gt;&lt;em&gt;The Value of Values&lt;/em&gt;&lt;/a&gt;, &lt;a href=&quot;https://www.youtube.com/watch?v=f84n5oFoZBc&quot;&gt;&lt;em&gt;Hammock-Driven Development&lt;/em&gt;&lt;/a&gt;, &lt;a href=&quot;https://www.youtube.com/watch?v=ScEPu1cs4l0&quot;&gt;&lt;em&gt;Are We There Yet?&lt;/em&gt;&lt;/a&gt;, and &lt;a href=&quot;https://www.youtube.com/watch?v=QCwqnjxqfmY&quot;&gt;&lt;em&gt;Design, Composition, and Performance&lt;/em&gt;&lt;/a&gt;. I highly recommend spending some time watching them, whether you choose Clojure or not.&lt;/p&gt;
&lt;p&gt;Some good books are &lt;a href=&quot;https://www.braveclojure.com/&quot;&gt;Clojure for the Brave and True&lt;/a&gt; by Daniel Higginbotham, which is free to read online and good for beginners. The one I bought is &lt;a href=&quot;https://www.amazon.com/dp/1617291412&quot;&gt;The Joy of Clojure&lt;/a&gt;, which is recommended for programmers who come from OOP languages like Java.&lt;/p&gt;
&lt;p&gt;For editors, VSCode has &lt;a href=&quot;https://calva.io/&quot;&gt;Calva&lt;/a&gt;, a complete and rich extension for Clojure. If you use Emacs you can use &lt;a href=&quot;https://cider.mx/&quot;&gt;Cider&lt;/a&gt;, plus there are extensions available for most editors/IDEs.&lt;/p&gt;
&lt;h2&gt;Racket&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://racket-lang.org/&quot;&gt;Racket&lt;/a&gt; is a modern dialect descended of &lt;em&gt;Scheme&lt;/em&gt;. While other Scheme dialects are generally small languages, Racket has evolved into a fully featured language with its own unique features.&lt;/p&gt;
&lt;p&gt;The code is compiled on every major platform and the language has been used in a lot of fields to create web applications, graphical interfaces, database integrations and mostly to quickly develop tools with graphics.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/img/racket-logo.svg&quot; alt=&quot;[Racket Logo]&quot; title=&quot;Racket logo.&quot;&gt;&lt;/p&gt;
&lt;p&gt;Racket is &lt;strong&gt;language-oriented&lt;/strong&gt;, which means it’s designed for creating &lt;a href=&quot;https://racket-lang.org/languages.html&quot;&gt;new programming languages&lt;/a&gt;. Every source file begins with &lt;code&gt;#lang&lt;/code&gt;, which defines the language used by that module. You can create entirely new languages with their own syntax and semantics, while still using the Racket ecosystem underneath. Other Lisp dialects can easily build DSLs, but they are tied to Lisp. Racket advances the concept by making it easy to define completely new languages, without requiring them to use Lisp syntax.&lt;/p&gt;
&lt;p&gt;Racket also comes with a wide range of features. It includes libraries for cross-platform GUIs, web servers, concurrency and parallelism, regular expressions, pattern matching, classes and objects, and an FFI for calling C code. Its package manager is integrated into the ecosystem, and a large collection of libraries is immediately available. Compared with other Lisp dialects, there is generally less setup required before you can start building something substantial.&lt;/p&gt;
&lt;p&gt;Racket offers an advanced macro system, providing the same kind of macro support as other dialects, plus hygienic macros. &lt;em&gt;Hygienic&lt;/em&gt; means that identifiers introduced by a macro don’t accidentally capture those in the surrounding code. This makes macros safer to write, especially for beginners, that don’t have to rely on &lt;code&gt;gensym&lt;/code&gt; like in the other dialects.&lt;/p&gt;
&lt;p&gt;Static typing is supported with &lt;a href=&quot;https://docs.racket-lang.org/ts-guide/&quot;&gt;Typed Racket&lt;/a&gt;, a typed variant of the language that lets programmers add type annotations and have their code checked before execution. Typed and untyped Racket modules can also work together, so typing can be introduced where it is useful without requiring an entire program to be rewritten.&lt;/p&gt;
&lt;p&gt;Even though Racket comes from the Scheme tradition and has strong functional programming roots, it supports multiple paradigms. Programs can be written using imperative programming, objects and classes, functional techniques, and metaprogramming.&lt;/p&gt;
&lt;p&gt;The language installation comes with &lt;a href=&quot;https://docs.racket-lang.org/drracket/&quot;&gt;DrRacket&lt;/a&gt;, a great IDE with everything ready to use the language, available on all major platforms. It combines an editor, REPL, and debugger, in a single programming environment for writing and testing Racket code.&lt;/p&gt;
&lt;p&gt;The main downsides are its small ecosystem and limited use in the industry. There are fewer libraries, projects and jobs compared to more popular languages. Performance and deployment can also be weaker points, especially compared with other compiled dialects.&lt;/p&gt;
&lt;h3&gt;Where Racket shines&lt;/h3&gt;
&lt;p&gt;Racket shines when designing new programming languages, building compilers and interpreters, or experimenting with new language features. This makes it particularly popular in computer science education and university research. Also, since it’s language-oriented, it’s a great choice when a program needs to provide a simple DSL, for example for customisation, without forcing the user to use a Lisp dialect.&lt;/p&gt;
&lt;p&gt;Racket is ideal for prototyping, scripting, and projects where having a comprehensive set of libraries and development tools immediately available is important. It’s worth noting that other dialects offer GUI support through external libraries and wrappers, while in Racket it is available out of the box.&lt;/p&gt;
&lt;h3&gt;Learning Resources&lt;/h3&gt;
&lt;p&gt;Racket has a rich website with a lot of helpful information. Important resources for beginners include &lt;a href=&quot;https://docs.racket-lang.org/quick/&quot;&gt;Quick: An Introduction to Racket with Pictures&lt;/a&gt; and &lt;a href=&quot;https://docs.racket-lang.org/guide/&quot;&gt;The Racket Guide&lt;/a&gt;, which is the complete guide to the language. Also worth mentioning is &lt;a href=&quot;https://beautifulracket.com/&quot;&gt;Beautiful Racket&lt;/a&gt; by Matthew Butterick, a visually curated guide to the language written by a passionate contributor. If you’re looking to write a compiler, check out &lt;a href=&quot;https://kmicinski.com/functional-programming/2025/11/23/build-a-language/&quot;&gt;this course&lt;/a&gt; using Racket.&lt;/p&gt;
&lt;p&gt;The best resource available for Scheme is &lt;a href=&quot;https://web.mit.edu/6.001/6.037/sicp.pdf&quot;&gt;SICP&lt;/a&gt;, also known as the &lt;em&gt;Wizard Book&lt;/em&gt;. It’s not only about Lisp, but it’s a great book for learning the fundamentals of programming and programming languages. It’s also worth mentioning a rather unusual book, &lt;a href=&quot;https://www.goodreads.com/en/book/show/548914.The_Little_Schemer&quot;&gt;The Little Schemer&lt;/a&gt;, which consists of a long series of questions that forces the reader to think before looking at the answer on the page.&lt;/p&gt;
&lt;h2&gt;Special Mention&lt;/h2&gt;
&lt;h3&gt;Elisp&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://learnxinyminutes.com/elisp/&quot;&gt;Elisp&lt;/a&gt; is a specialised dialect that’s part of Emacs and is used to customise the editor. It’s an old Lisp dialect that comes with quite a few limitations, but it’s probably one of the best practical uses I’ve ever found for Lisp, beyond using it as a general-purpose programming language. It’s used to customise and extend the functionality of Emacs, since much of the editor itself is written in Elisp. By evaluating Elisp code inside it, you can change how Emacs looks and behaves in real time, without requiring a reload.&lt;/p&gt;
&lt;h4&gt;Learning resources&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://www.gnu.org/software/emacs/manual/eintr.html&quot;&gt;An Introduction to Programming in Emacs Lisp&lt;/a&gt; is freely available online. Another useful resource is &lt;a href=&quot;https://protesilaos.com/emacs/emacs-lisp-elements&quot;&gt;Emacs Lisp Elements&lt;/a&gt; by Protesilaos Stavrou, an active Emacs contributor and advocate.&lt;/p&gt;
&lt;h2&gt;Syntax comparison&lt;/h2&gt;
&lt;p&gt;We can use a simple instruction interpreter to show some of the syntactic differences between the dialects.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-lisp&quot;&gt;(defun calculate (instructions)
  (loop with result = 0
        for (operation value) in instructions
        do (setf result
                 (case operation
                   (add      (+ result value))
                   (subtract (- result value))
                   (multiply (* result value))))
        finally (return result)))

(calculate &amp;#39;((add 5) (multiply 3) (subtract 4))) ;; =&amp;gt; 11
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In Common Lisp, I used the &lt;code&gt;LOOP&lt;/code&gt; macro to iterate over and destructure each instruction, then perform the operation by updating local state. Notice that it carries an accumulator (&lt;code&gt;result&lt;/code&gt;) through the sequence, essentially doing the same job as a &lt;code&gt;reduce&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-clojure&quot;&gt;(defn calculate [instructions]
  (reduce
    (fn [result [operation value]]
      (case operation
        :add      (+ result value)
        :subtract (- result value)
        :multiply (* result value)))
    0
    instructions))

(calculate [[:add 5] [:multiply 3] [:subtract 4]]) ;; =&amp;gt; 11
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In Clojure, I used a reduction over the sequence of instructions. Notice that it doesn’t use or update any local state, since the reduction uses immutable accumulation. I also used some syntax that is specific to Clojure, such as vectors &lt;code&gt;[]&lt;/code&gt; and keywords like &lt;code&gt;:add&lt;/code&gt;, and destructured the contents of each vector with &lt;code&gt;[operation value]&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-racket&quot;&gt;(define (calculate instructions)
  (for/fold ([result 0])
            ([instruction (in-list instructions)])
    (match instruction
      [(list &amp;#39;add value)
       (+ result value)]
      [(list &amp;#39;subtract value)
       (- result value)]
      [(list &amp;#39;multiply value)
       (* result value)])))

(calculate &amp;#39;((add 5) (multiply 3) (subtract 4))) ;; =&amp;gt; 11
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In Racket, we use &lt;code&gt;for/fold&lt;/code&gt; to iterate over the instructions while carrying the result from one iteration to the next. We also use pattern matching with &lt;code&gt;match&lt;/code&gt; to destructure each instruction and identify the operation at the same time. For example, &lt;code&gt;(list &amp;#39;add value)&lt;/code&gt; matches a two-element list whose first element is the symbol &lt;code&gt;add&lt;/code&gt; and binds the second element to &lt;code&gt;value&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Which one to pick?&lt;/h2&gt;
&lt;p&gt;To summarise the above:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Clojure&lt;/strong&gt; gives you modern syntax, functional programming and immutable data structures, great tooling and libraries, an almost drop-in replacement for Java, a full-stack language, a strong community, and maybe even a job.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Common Lisp&lt;/strong&gt; gives you native compilation, high performance, the most powerful REPLs, multi-paradigm programming, and a stable, battle-tested language.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Racket&lt;/strong&gt; gives you a feature rich language, a great IDE for beginners, a cross-platform GUI, a powerful platform for building new languages and DSLs, easily approachable for students.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Elisp&lt;/strong&gt; gives you the ability to extend and customise Emacs.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For most programmers looking for a practical and elegant Lisp they could use professionally, &lt;strong&gt;Clojure is probably the safest first choice&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;If you want to experience the traditional Lisp development model at its fullest, you want native compilation without rely on JVM, an exceptionally interactive environment and a huge language, choose &lt;strong&gt;Common Lisp&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;If you are a computer science student, interested in compilers and programming-language design, or if you need a quick way to write tools or need an easy way to use a cross-platform GUI, choose &lt;strong&gt;Racket&lt;/strong&gt;. This is probably the easiest to start with between the dialects.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;If you have any questions of feedback, please send me an email.&lt;/p&gt;
</content:encoded></item><item><title>A Road to Lisp: Why Lisp</title><link>https://scotto.me/blog/2026-07-09-why-lisp/</link><guid isPermaLink="true">https://scotto.me/blog/2026-07-09-why-lisp/</guid><description>Why Lisp</description><pubDate>Thu, 09 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The question that most programmers face when seeing some Lisp code for the first time is, without doubt, “what the hell is this?”. I asked myself the same thing when I first read its unconventional syntax: all those parentheses, the weird indentation, and who thought to use the first argument of &lt;code&gt;format&lt;/code&gt; to print to stdout?&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-lisp&quot;&gt;(defun flip-coin-for-real ()
  (&amp;lt;= (random 100) 80))

(defun hello-lisp ()
  (write-line &amp;quot;What is your name?&amp;quot;)
  (let ((name (read-line))
	    (learn-it (if (flip-coin-for-real)
		              &amp;quot;should&amp;quot;
		              &amp;quot;should not&amp;quot;)))
    (format t &amp;quot;Hello, ~A.~%&amp;quot; name)
    (format t &amp;quot;The Oracle said... you ~A learn Lisp!~%&amp;quot; learn-it)))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After getting comfortable reading code with so many parentheses, I had to learn how to use packages and symbols, how to create new projects and import libraries, how to use the REPL, and how to use conditions and restarts. Most importantly, I had to switch to a new way of thinking when constructing algorithms.&lt;/p&gt;
&lt;p&gt;The Lisp journey has a steep learning curve compared to most common languages. But it can also unlock skills that those languages never will. Why? Because &lt;strong&gt;in Lisp you can do things that are not possible in other languages&lt;/strong&gt;. Lisp enables new possibilities and allows algorithms to take different shapes, giving the programmer more power and flexibility.&lt;/p&gt;
&lt;p&gt;Paul Graham coined the term &lt;a href=&quot;https://paulgraham.com/avg.html&quot;&gt;Blub paradox&lt;/a&gt; to explain why it is difficult for programmers who have only used less powerful languages to understand the power of Lisp. In short, it’s because they are missing the concepts needed to perceive what is lacking in those languages and the advantage Lisp has over them. Louis Armstrong said something similar about jazz:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you have to ask what jazz is, you&amp;#39;ll never know.
— Louis Armstrong.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In this article, I&amp;#39;ll explain a few features that show why this special language is worth learning. It&amp;#39;s not an easy path, and to truly grasp its power you&amp;#39;ll need to use Lisp yourself. And even if you don’t end up using Lisp, you will gain a different perspective on what programming languages can do.&lt;/p&gt;
&lt;p&gt;Lisp is going to make you a better programmer because &lt;strong&gt;it changes the way you think about problems using code&lt;/strong&gt;. To be more specific, it will teach you an approach that is not possible with other programming languages. You will be able to program Lisp itself and thus adapt the language you use to the problems you are solving. Using Lisp, you will learn to &lt;em&gt;grow the language toward your problem, then write the program in that language&lt;/em&gt;.&lt;/p&gt;
&lt;h2&gt;Extensibility&lt;/h2&gt;
&lt;p&gt;Lisp is extensible within itself. Experts — called lispers — commonly refer to it as &lt;em&gt;the programmable programming language&lt;/em&gt;[^1]. Not only will you write code for your programs, but you can write code that extends Lisp itself.&lt;/p&gt;
&lt;p&gt;This is possible thanks to the &lt;em&gt;macro&lt;/em&gt; operator. If you&amp;#39;ve used macros before in languages like C, Rust, or Swift, don’t expect the same thing. Those macros are primarily a way to eliminate boilerplate or generate repetitive code. Beyond that, macros in Lisp allow you to create new constructs that become part of the language itself.&lt;/p&gt;
&lt;p&gt;They are one of the hardest features to master for Lisp programmers, so I won&amp;#39;t try to teach you how to use them or how they work here. I just want to give you a taste of what they do. For example, C programmers might want to use the &lt;code&gt;while&lt;/code&gt; operator to define a simple loop. Common Lisp does not provide it, so the programmer can write a macro and add it to the language.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-lisp&quot;&gt;(defmacro while (condition &amp;amp;body body)
  `(loop while ,condition do
     (progn ,@body)))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The new &lt;code&gt;while&lt;/code&gt; macro executes a series of instructions (the &lt;code&gt;body&lt;/code&gt;) for as long as the &lt;code&gt;condition&lt;/code&gt; is true. It uses &lt;code&gt;loop&lt;/code&gt;, which is itself a macro used to write complex iterations (notice that it uses a &lt;code&gt;while&lt;/code&gt; symbol as well). &lt;code&gt;progn&lt;/code&gt; is a special form that takes multiple expressions, runs them in order, and returns the result of the last one.&lt;/p&gt;
&lt;p&gt;Instead of writing &lt;code&gt;(loop while ... do (progn ...))&lt;/code&gt;, we can use the new &lt;code&gt;while&lt;/code&gt; operator, shortening the code and making it similar to C. We just extended the language available to us.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-lisp&quot;&gt;(let ((counter 3))
  (while (&amp;gt; counter 0)
    (print counter)
    (decf counter)))

;; 3
;; 2
;; 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The beginner might not grasp what is really magical here, since, other than the unique syntax, &lt;code&gt;defmacro&lt;/code&gt; looks pretty similar to &lt;code&gt;defun&lt;/code&gt;, which was used in the first code example to define new functions.&lt;/p&gt;
&lt;p&gt;To better understand the difference between the two, let’s define a new &lt;code&gt;while&lt;/code&gt; as a function, then call it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-lisp&quot;&gt;(defun fake-while (condition body)
  (loop while condition do
    (funcall body)))
    
(let ((counter 3))
  (fake-while (&amp;gt; counter 0) 
	(progn
	  (print counter)
	  (decf counter))))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;loop&lt;/code&gt; is the same macro we used before; &lt;code&gt;funcall&lt;/code&gt; calls the function received as the first parameter, in this case &lt;code&gt;body&lt;/code&gt;. Try to execute the code above in a Common Lisp REPL. You will receive a condition of type error, similar to this: &lt;code&gt;The value 2 is not of type FUNCTION&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This happens because the arguments to &lt;code&gt;fake-while&lt;/code&gt; are evaluated immediately. &lt;code&gt;(&amp;lt; x 3)&lt;/code&gt; evaluates to &lt;code&gt;t&lt;/code&gt; -- true. Because &lt;code&gt;progn&lt;/code&gt; is a function, its arguments are evaluated. &lt;code&gt;(print counter)&lt;/code&gt; prints &lt;code&gt;3&lt;/code&gt;, and &lt;code&gt;(decf counter)&lt;/code&gt; returns &lt;code&gt;2&lt;/code&gt;. Since &lt;code&gt;progn&lt;/code&gt; returns the value of its last expression, &lt;code&gt;body&lt;/code&gt; becomes &lt;code&gt;2&lt;/code&gt;. So fake-while receives &lt;code&gt;t&lt;/code&gt; as its first argument and &lt;code&gt;2&lt;/code&gt; as its second, not a block of code. It will enter the &lt;code&gt;while&lt;/code&gt; since the condition is true, and then &lt;code&gt;funcall&lt;/code&gt; expects &lt;code&gt;body&lt;/code&gt; to be the function to be called, but &lt;code&gt;body&lt;/code&gt; is the value &lt;code&gt;2&lt;/code&gt;. This raises the condition above. The code executed by the compiler is the one below. &lt;code&gt;(funcall 2)&lt;/code&gt; raises the condition.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-lisp&quot;&gt;(loop while t
	  do (funcall 2))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The macro &lt;code&gt;while&lt;/code&gt; defined earlier works because it keeps the arguments — &lt;code&gt;condition&lt;/code&gt; and &lt;code&gt;body&lt;/code&gt; — intact, without evaluating them until needed. We can inspect the transformation that a macro operates in the REPL. This transformation is called &lt;em&gt;expansion&lt;/em&gt;. &lt;code&gt;macroexpand&lt;/code&gt; is a special Lisp command we can use to expand code.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-lisp&quot;&gt;CL-USER&amp;gt; (macroexpand-1 &amp;#39;(while (&amp;gt; counter 0) (print counter) (decf counter)))
(LOOP WHILE (&amp;gt; COUNTER 0)
      DO (PROGN (PRINT COUNTER) (DECF COUNTER)))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The code returned from the macro expansion is the one received and executed by the compiler. We can see that this time the &lt;code&gt;while&lt;/code&gt; macro preserved the arguments so they will be executed together with the rest of the code.&lt;/p&gt;
&lt;p&gt;A macro, unlike a function, does not evaluate the arguments in advance. Instead, it treats them as pure data. This is possible because (almost) everything you see in Lisp is made of lists. They are the main data structure, and they are used to write code.&lt;/p&gt;
&lt;h2&gt;It’s lists all the way down&lt;/h2&gt;
&lt;p&gt;Programs in Lisp are composed of a series of &lt;strong&gt;symbolic expressions&lt;/strong&gt; (abbreviated &lt;em&gt;s-expr&lt;/em&gt;). &lt;em&gt;Expression&lt;/em&gt; is a mathematical term meaning anything that evaluates to a value; &lt;em&gt;symbolic&lt;/em&gt; means that expressions are created using values and symbols.&lt;/p&gt;
&lt;p&gt;An &lt;em&gt;s-expression&lt;/em&gt; is one of two things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;an &lt;em&gt;atom&lt;/em&gt;, which is a unit of data (a number, a string, a symbol, etc)&lt;/li&gt;
&lt;li&gt;a &lt;em&gt;list&lt;/em&gt;, which is a collection of elements that can be atoms or other lists&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-lisp&quot;&gt;1           ;; An atom number
&amp;quot;hello&amp;quot;     ;; An atom string
&amp;#39;(1 &amp;quot;y&amp;quot; :c) ;; A list of atoms (a number, a string, a keyword)
(+ 1 2)     ;; A list composed of a symbol (plus) and two numbers
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Lisp means &lt;em&gt;LISt Processing&lt;/em&gt;, so the purpose of the language is to process the series of instructions expressed as lists that compose the program.&lt;/p&gt;
&lt;p&gt;Since lists are used both as the main data structure and to write the code, we can extract an interesting property of the language. In Lisp, &lt;strong&gt;code-as-data&lt;/strong&gt; means that both code and data are expressed using lists. This property is called &lt;strong&gt;homoiconicity&lt;/strong&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-lisp&quot;&gt;CL-USER&amp;gt; (+ 1 2)
3
CL-USER&amp;gt; &amp;#39;(+ 1 2)
(+ 1 2)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I’ve used two lists with the same content; the only difference is that I put &lt;code&gt;&amp;#39;&lt;/code&gt; in front of the second one, but the output is different. The first list is treated as &lt;em&gt;code&lt;/em&gt;. It gets evaluated, and specifically the symbol &lt;code&gt;+&lt;/code&gt; maps to a function that performs the sum of the arguments. Lisp uses what’s called &lt;a href=&quot;https://en.wikipedia.org/wiki/Polish_notation&quot;&gt;&lt;em&gt;Polish notation&lt;/em&gt;&lt;/a&gt;, where the function name is the first element of the list and what follows are the arguments. So instead of writing &lt;code&gt;print(&amp;quot;hello&amp;quot;)&lt;/code&gt;, we write &lt;code&gt;(print &amp;quot;hello&amp;quot;)&lt;/code&gt;, moving the function name inside the parentheses. The output is 3, which is the result of the code execution.&lt;/p&gt;
&lt;p&gt;The second list is treated as &lt;em&gt;data&lt;/em&gt;. &lt;code&gt;&amp;#39;&lt;/code&gt; is an operator that tells the interpreter not to evaluate the following list and keep it as manipulable data. The output is the same list, not evaluated.&lt;/p&gt;
&lt;p&gt;The subtle distinction between code and data is what makes macros possible. We can manipulate code as we manipulate data. By transforming the source code, we are able to write &lt;strong&gt;programs that write programs&lt;/strong&gt;, a capability other languages have spent decades trying to imitate.&lt;/p&gt;
&lt;p&gt;Extending the language means that by creating new constructs that are more expressive for your program&amp;#39;s specific scope, you can make your code more &lt;em&gt;concise&lt;/em&gt;. Repetitive boilerplate code can be replaced with custom macros to shorten the code and save time. New control structures can be created to control resource access and the evaluation of forms. Macros can generate code, improve performance, and, most importantly, create new syntactic abstractions that are easier to use to hide complex and error-prone code.&lt;/p&gt;
&lt;h2&gt;A live system&lt;/h2&gt;
&lt;p&gt;Lisp is not only a programming language, it&amp;#39;s a &lt;strong&gt;live system&lt;/strong&gt;. To clarify this point, let’s start with how different the workflow is between Lisp and other languages.&lt;/p&gt;
&lt;p&gt;With other languages, you open the project in the editor and start writing code. The first thing a lisper does is start a Lisp process, attach it to the REPL, and then load the project into that process.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;Read-Eval-Print Loop&lt;/strong&gt; is an interactive environment used to evaluate code and immediately see the result. It&amp;#39;s a window into the Lisp living process that is currently running your program.&lt;/p&gt;
&lt;p&gt;In other languages, once you change the code, you have to stop and compile it, then run the project to observe, test, and debug the changes. If something&amp;#39;s wrong, you go back to the write-compile-run-debug cycle.&lt;/p&gt;
&lt;p&gt;Instead, a lisper continuously evaluates code in the running process and observes the output directly in the REPL, since &lt;strong&gt;the Lisp process is the running program&lt;/strong&gt;. Every single function can be immediately tested in the REPL as a single unit of code, as well as any other action useful for development, such as querying a database, inspecting variables, or debugging.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/img/REPL.png&quot; alt=&quot;[Lisp REPL]&quot; title=&quot;An example of REPL use with Calva and Clojure. Evaluation results are printed near each lines, as well as in the output window.&quot;&gt;&lt;/p&gt;
&lt;p&gt;A Lisp process is usually kept alive for weeks on end since there is no need to stop it. It can stay attached to the REPL in the editor for as long as needed. New functions, macros, and variables are continuously defined and redefined, a process called &lt;em&gt;binding&lt;/em&gt; within an internal memory called the &lt;em&gt;environment&lt;/em&gt;. This particular workflow even has a name: &lt;strong&gt;REPL-driven development&lt;/strong&gt;. This is a real killer feature. It has been available in Lisp since its invention in the 60s, and it has been imitated by other languages (where possible), like many other Lisp original features.&lt;/p&gt;
&lt;p&gt;Does the word &lt;em&gt;hot-reloading&lt;/em&gt; tell you anything? I’ve been lucky since I started my career working with web frontends, where the JavaScript code of the app is hot-reloaded with every hard refresh of the page. And thanks to modern tools, I now only need to &lt;em&gt;save a file&lt;/em&gt; and the webpage will automatically refresh itself with the new changes. Under the hood, hot-reloading means there is a process watching the files, recompiling the modules that changed, and a websocket connection is used to inject the changes silently into the page. But not all software stacks are that lucky. Some backend frameworks still require recompilation, the situation is mixed for desktop and mobile development, and low-level languages require full compilation every time.&lt;/p&gt;
&lt;p&gt;In Lisp, hot-reloading is not a separate tool or technique. It comes for free when evaluating code in the live environment. Every time I redefine a symbol, it picks up the new definition, whether it’s a function, data, or a macro. I don’t need to stop and compile, run tests separately, or use some special debugger. Everything comes automatically by evaluating in the REPL. A good analogy is that programming in Lisp is like &lt;em&gt;evolving&lt;/em&gt; a program rather than constructing it. Once a new Lisp process has started and code gets evaluated into it, that system will become the program itself.&lt;/p&gt;
&lt;p&gt;Lisp allows you to approach programming in a new way. You can evolve the programs while writing them, and at the same time, as discussed before, evolve the language to your needs. A Lisp CAD program has evolved by turning Lisp into a language that writes CAD programs. A high-frequency trading system has evolved with a language adapted to write similar trading systems. This is the nature of Lisp, and it offers many advantages.&lt;/p&gt;
&lt;h2&gt;Extensible software&lt;/h2&gt;
&lt;p&gt;This is something probably even less known, but the two features explained above (language extensibility and the Lisp live system) allow you to easily &lt;strong&gt;create extensible software&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;We&amp;#39;re used to desktop programs being extensible mainly through plugins, such as in text editors, or sometimes through scripting languages for customization, as in game modding. These solutions usually work well, but they require programmers to design and maintain an entire system for extensibility, and they require users to learn a specific set of APIs to write plugins or extensions. In Lisp, this comes almost for free.&lt;/p&gt;
&lt;p&gt;While extending the language, lispers write macros to encapsulate actions and make code easy to reuse. In doing so, beyond just creating new symbols, they are effectively writing a &lt;strong&gt;DSL&lt;/strong&gt;, a &lt;em&gt;domain-specific language&lt;/em&gt; for the program. When lispers need to make their software extensible, all they need to do is let users use the DSL they&amp;#39;ve created.&lt;/p&gt;
&lt;p&gt;To understand this concept, let’s look at some use case scenarios. I wrote a custom CMS server for clients’ websites. I wrote some macros for generating webpages server-side.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-lisp&quot;&gt;(html
  (:h1 &amp;quot;Lorem Ipsum&amp;quot;)
  (:p &amp;quot;Dolor sit &amp;quot; (:b &amp;quot;amet&amp;quot;) &amp;quot;.&amp;quot;))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I can expose the same DSL I’ve written internally to the users so they can write their own views and customise their CMS instance.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-lisp&quot;&gt;;; A user can write dynamic pages using the full power of Lisp
(let ((user-name &amp;quot;Alice&amp;quot;)
      (items &amp;#39;(&amp;quot;Apples&amp;quot; &amp;quot;Bananas&amp;quot; &amp;quot;Oranges&amp;quot;)))
  (html
    (:h1 (format nil &amp;quot;Welcome back, ~A!&amp;quot; user-name))
    (:ul (dolist (item items)
           (html (:li item))))))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice how the &lt;code&gt;html&lt;/code&gt; macro seamlessly integrates with Lisp&amp;#39;s variables (&lt;code&gt;user-name&lt;/code&gt;), loops (&lt;code&gt;dolist&lt;/code&gt;), and string formatting (&lt;code&gt;format&lt;/code&gt;). In a traditional templating language, you&amp;#39;d need to learn a separate syntax with special brackets like &lt;code&gt;{{ user_name }}&lt;/code&gt; or &lt;code&gt;{% for %}&lt;/code&gt;. In Lisp, you don&amp;#39;t need a new language since you just use Lisp itself to build your templates.&lt;/p&gt;
&lt;p&gt;This integration means your DSL inherits all the power of Lisp: conditionals, recursion, higher-order functions, and even the ability to debug your templates step-by-step in the REPL.&lt;/p&gt;
&lt;p&gt;Another scenario: I wrote a math software where users can write formulas and the program renders them on a Cartesian graph. So I wrote a DSL to write math and draw. I can expose a small subset of the language to users so they can draw directly without having to use math formulas.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-lisp&quot;&gt;(graph
  (:curve (lambda (x) (* x x)) 0 0)     ; plot y = x²
  (:point 0 0))                         ; mark the origin
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this DSL, users can draw complex mathematical functions with minimal code. Since it&amp;#39;s just Lisp, they can use variables, define helper functions, or even generate multiple curves in a loop. This gives the users a clean interface while leaving the complex rendering code safely hidden away.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/img/lisp_dsl_parabola_on_graph.svg&quot; alt=&quot;[A parabola on a Cartesian graph]&quot;&gt;&lt;/p&gt;
&lt;p&gt;This technique for extending programs has been used successfully. AutoCAD uses &lt;em&gt;AutoLISP&lt;/em&gt; to automate repeating tasks and create complex geometries. Emacs is the most extensible text editor that has ever existed on this planet, and most of it is implemented in its own Lisp dialect in order to make it infinitely expandable. There&amp;#39;s a running joke that hardcore Emacs users never have to leave the editor because it already contains everything they would ever need. In fact, Emacs has been extended to be a PDF reader, a web browser, an email client, an RSS reader, a terminal multiplexer, a Git client, a music player, a chat client, a spreadsheet, an IRC client, and even a window manager for your entire desktop, all thanks to using Lisp under the hood[^2].&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The most powerful programming language is Lisp. If you don&amp;#39;t know Lisp, you don&amp;#39;t know what it means for a programming language to be powerful and elegant. Once you learn Lisp, you will see what is lacking in most other languages.
— &lt;a href=&quot;https://stallman.org/stallman-computing.html&quot;&gt;R. M. Stallman&lt;/a&gt; creator of GCC, Emacs, the GNU project.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;So why Lisp (or when)&lt;/h2&gt;
&lt;p&gt;A lot of people have argued that one day in the future there would be a time for Lisp. A time where it becomes popular, almost the default language, when the majority of programmers will come to appreciate what a fantastic experience it is to work with it. A time when Lisp would be taught at universities all over the world so companies would have no issues finding lispers, and engineers would become unafraid of incompatibility or performance issues. Programmers would joyfully spend their days using REPL-driven development, and most of the software we use would become extensible using variations of a single language.&lt;/p&gt;
&lt;p&gt;This time never happened, and probably never will.&lt;/p&gt;
&lt;p&gt;Still, Lisp has survived from the 60s, becoming the second oldest programming language still in use after Fortran. So many languages were inspired by it, and so many languages are still being created, missing some of the features that helped Lisp survive. So even if there isn&amp;#39;t a time for Lisp, that doesn&amp;#39;t mean it&amp;#39;s not a powerful language worth knowing.&lt;/p&gt;
&lt;p&gt;Better programmers than me have said that it&amp;#39;s hard to justify Lisp&amp;#39;s use by picking a single feature among its extensibility, its interactive environment, the REPL, and a lot of other features we haven&amp;#39;t touched yet. It is &lt;strong&gt;the combination of all of them&lt;/strong&gt; that makes Lisp programming what it is.&lt;/p&gt;
&lt;p&gt;So get ready to learn what the most powerful programming language truly is.&lt;/p&gt;
&lt;p&gt;[^1]: This quote belongs to John Foderaro, co-founder of &lt;a href=&quot;https://franz.com/enterprise_development_tools.lhtml&quot;&gt;Franz Lisp&lt;/a&gt;.
[^2]: To be fair, &lt;a href=&quot;https://en.wikipedia.org/wiki/Editor_war&quot;&gt;some people&lt;/a&gt; argue that Emacs is &amp;quot;a great operating system, lacking only a decent editor&amp;quot;.&lt;/p&gt;
</content:encoded></item><item><title>A simple Common Lisp web app</title><link>https://scotto.me/blog/2025-04-30-a-simple-common-lisp-web-app/</link><guid isPermaLink="true">https://scotto.me/blog/2025-04-30-a-simple-common-lisp-web-app/</guid><description>A tutorial for the web</description><pubDate>Wed, 30 Apr 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;One of the drawbacks I’ve found when dealing with Common Lisp is the lack of documentation available. Too often, I find published libraries without an explanation of how they are meant to be used or only partially documented, and I need to dig into the source code to understand what they do and to see all the functions available. Even though reading source code is a proven technique to improve one&amp;#39;s grasp of a programming language, most other systems come with extensively documented libraries, something appreciated by beginners and a factor that often contributes to a language&amp;#39;s popularity.&lt;/p&gt;
&lt;p&gt;In my opinion, this lack of good documentation is one of the reasons Common Lisp is often seen as challenging for beginners, which makes it harder for the language to become popular.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/img/lisp_cycles.png&quot; alt=&quot;xkcd.com/224&quot; title=&quot;xkcd.com/224&quot;&gt;&lt;/p&gt;
&lt;p&gt;Some time ago, when I looked for guidance on writing a generic web app, I was surprised by the absence of a quickstart page to help me set up a simple server—something the Python community has provided for &lt;a href=&quot;https://flask.palletsprojects.com/en/stable/quickstart/&quot;&gt;Flask&lt;/a&gt; for many years.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“The most underrated skill to learn as an engineer is how to document. Fuck, someone please teach me how to write good documentation. Seriously, if there&amp;#39;s any recommendations, I&amp;#39;d seriously pay for a course (like probably a lot of money, maybe 1k for a course if it guaranteed that I could write good docs.)”
&lt;a href=&quot;https://www.reddit.com/r/ExperiencedDevs/comments/nmodyl/drunk_post_things_ive_learned_as_a_sr_engineer/&quot;&gt;A drunk dev on reddit&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So I put together a short tutorial on how to build a simple web app in Common Lisp, inspired by the Clojure tutorial written for &lt;a href=&quot;https://luminusweb.com/docs/guestbook&quot;&gt;Luminus&lt;/a&gt;. The goal is to write a guestbook demo, involving template &lt;em&gt;rendering&lt;/em&gt;, connecting to a database to run queries, and exposing routes to the webpage.&lt;/p&gt;
&lt;p&gt;To follow the tutorial, you need a Common Lisp implementation, like &lt;a href=&quot;https://www.sbcl.org/&quot;&gt;SBCL&lt;/a&gt;, with &lt;a href=&quot;https://www.quicklisp.org/index.html&quot;&gt;Quicklisp&lt;/a&gt;, the dependency manager. I also recommend having a REPL integrated with your IDE, like &lt;a href=&quot;https://github.com/joaotavora/sly&quot;&gt;SLY&lt;/a&gt; for Emacs or &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=rheller.alive&quot;&gt;Alive&lt;/a&gt; for VSCode.&lt;/p&gt;
&lt;p&gt;I’ll use more modern CL libraries that have an interface similar to other languages, so it might be a bit easier to follow along.&lt;/p&gt;
&lt;h2&gt;The server&lt;/h2&gt;
&lt;p&gt;First things first, I created a new Common Lisp project. To do that with a simple boilerplate, I loaded &lt;code&gt;cl-project&lt;/code&gt; in the environment and called the function &lt;code&gt;make-project&lt;/code&gt; with a path and a name for the project.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-lisp&quot;&gt;&amp;gt; (ql:quickload :cl-project)
To load &amp;quot;cl-project&amp;quot;:
  Load 1 ASDF system:
    cl-project
; Loading &amp;quot;cl-project&amp;quot;
..
(:CL-PROJECT)

&amp;gt; (cl-project:make-project #P&amp;quot;~/guestbook/&amp;quot; :name &amp;quot;guestbook&amp;quot;)
writing ~/guestbook/guestbook.asd
writing ~/guestbook/README.org
writing ~/guestbook/README.markdown
writing ~/guestbook/.gitignore
writing ~/guestbook/src/main.lisp
writing ~/guestbook/tests/main.lisp
T
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then I ran this command to let Quicklisp know where my new project is located.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-lisp&quot;&gt;&amp;gt; (pushnew #P&amp;quot;~/guestbook/&amp;quot; asdf:*central-registry* :test #&amp;#39;equal)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I declared the required libraries in the &lt;code&gt;:depends-on&lt;/code&gt; property so that Quicklisp would download them from the repo and load them into the environment.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-lisp&quot;&gt;(defsystem &amp;quot;guestbook&amp;quot;
  :version &amp;quot;0.0.1&amp;quot;
  :license &amp;quot;MIT&amp;quot;
  :depends-on (:alexandria        ;; utils
               :uiop
               :cl-ppcre          ;; regex library
               :cl-syntax-annot   ;; for @export annotation
               :clack             ;; Web libraries
               :lack
               :caveman2          ;; Web framework
               :djula             ;; Template engine
               :cl-dbi)           ;; Database
  :components ((:module &amp;quot;src&amp;quot;
                :components
                ((:file &amp;quot;config&amp;quot;) ;; files into src/
                 (:file &amp;quot;db&amp;quot;)
                 (:file &amp;quot;web&amp;quot;)
                 (:file &amp;quot;core&amp;quot;))))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, inside &lt;code&gt;src/core.lisp&lt;/code&gt; (I renamed the file from &lt;code&gt;main&lt;/code&gt; to &lt;code&gt;core&lt;/code&gt;) I added two new functions, to start and stop the server, which will be helpful to use from the REPL.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-lisp&quot;&gt;(defvar *server* nil)

(defparameter *app*
  (lack:builder
	  (:static
      :path (lambda (path)
              (if (ppcre:scan 
                    &amp;quot;^(?:/images/|/css/|/js/|/robot\\.txt$|/favicon\\.ico$)&amp;quot; 
                    path)
                  path
                  nil))
      :root *static-directory*)
  ;; Additional middlewares
    guestbook.web:*web*))

@export
(defun start (&amp;amp;rest args
              &amp;amp;key
                (server :hunchentoot)
                (port 3210)
                (debug nil)
              &amp;amp;allow-other-keys)
  &amp;quot;Starts the server.&amp;quot;
  (when *server*
    (restart-case (error &amp;quot;Server is already running.&amp;quot;)
      (restart-server ()
        :report &amp;quot;Restart the server.&amp;quot;
        (stop))))

  (setf *server* (apply #&amp;#39;clack:clackup *app*
                   :server server
                   :port port
                   :debug debug
                   args))
  (format t &amp;quot;Server started&amp;quot;))

@export
(defun stop ()
  &amp;quot;Stops the server.&amp;quot;
  (when *server*
    (clack:stop *server*)
    (format t &amp;quot;Server stopped&amp;quot;)
    (setf *server* nil)))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;*server*&lt;/code&gt; contains the server instance and is defined as a variable since we will need to redefine it. &lt;code&gt;*app*&lt;/code&gt; is the web application wrapped with a layer by &lt;em&gt;Lack&lt;/em&gt;. &lt;code&gt;start&lt;/code&gt; and &lt;code&gt;stop&lt;/code&gt; instantiate the server with some logging, or raise errors if the action is not successful.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Lack&lt;/em&gt; and &lt;em&gt;Clack&lt;/em&gt; are the two libraries I used to wrap the web application. &lt;a href=&quot;https://github.com/fukamachi/lack&quot;&gt;The first one&lt;/a&gt; allows to define a series of middlewares in the server; for example, I used &lt;code&gt;:static&lt;/code&gt; to tell the server where to find all the static assets in the project, inside the directory pointed to by &lt;code&gt;*static-directory*&lt;/code&gt;. Other middlewares are available, like logging, managing sessions or providing authentication features. &lt;a href=&quot;https://github.com/fukamachi/clack&quot;&gt;&lt;em&gt;Clack&lt;/em&gt;&lt;/a&gt; instead is an abstraction layer for the server that provides some parameters to customise it, for example, to quickly swap which server to use between development mode (&lt;code&gt;hunchentoot&lt;/code&gt;) and production (&lt;code&gt;woo&lt;/code&gt;).&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-lisp&quot;&gt;(unless (null *server*)
    (restart-case (error &amp;quot;Server is already running.&amp;quot;)
      (restart-server ()
        :report &amp;quot;Restart the server.&amp;quot;
        (stop))))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this portion of the code, I defined a restart action for the debugger. The Common Lisp debugger always has &lt;code&gt;RETRY&lt;/code&gt; and &lt;code&gt;ABORT&lt;/code&gt; actions for every exception raised. By declaring a &lt;code&gt;restart-case&lt;/code&gt;, we are signalling an error and adding custom choices to the ones offered by default by the debugger. The new option I added is called &lt;code&gt;restart-server&lt;/code&gt; and, if selected, it first &lt;code&gt;(stop)&lt;/code&gt;s the server and then restarts the operation, so the function runs again without raising an error. It’s a smart way to interact with the REPL and improve the developer experience using the language directly.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/img/cl-restart-case-server.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;More on conditions and restart &lt;a href=&quot;https://gigamonkeys.com/book/beyond-exception-handling-conditions-and-restarts&quot;&gt;here&lt;/a&gt; and &lt;a href=&quot;https://lispcookbook.github.io/cl-cookbook/error_handling.html&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;At the top of &lt;code&gt;src/core.lisp&lt;/code&gt; I set the package definition and some initialisation function calls.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-lisp&quot;&gt;(in-package :cl-user)
(defpackage guestbook.core
  (:use :cl)
  (:import-from :guestbook.config
                :*static-directory*))
(in-package :guestbook.core)

(syntax:use-syntax :annot)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;(syntax:use-syntax :annot)&lt;/code&gt;, from the package &lt;code&gt;cl-syntax-annot&lt;/code&gt;, allows us to use some special decoration notation at the top of the function. At the top of &lt;code&gt;start&lt;/code&gt; and &lt;code&gt;stop&lt;/code&gt; I added an &lt;code&gt;@export&lt;/code&gt; tag, which tells the compiler that a function is exported by the package. &lt;/p&gt;
&lt;h2&gt;Configuration&lt;/h2&gt;
&lt;p&gt;I put the configuration parameters for the app into a config file; there are better ways, but they’re not necessary for a project this simple.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-lisp&quot;&gt;@export
(defparameter *application-root* 
  (asdf:system-source-directory :guestbook))
@export
(defparameter *static-directory* 
  (merge-pathnames #P&amp;quot;static/&amp;quot; *application-root*))
@export
(defparameter *template-directory* 
  (merge-pathnames #P&amp;quot;templates/&amp;quot; *application-root*))

@export
(defvar *config*
  `(:databases 
      ((:maindb :sqlite3 
        :database-name ,(namestring (merge-pathnames &amp;quot;guestbook.sqlite&amp;quot;
                                                     *application-root*))))
    :schema-file &amp;quot;db/schema.sql&amp;quot;))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The variable &lt;code&gt;*config*&lt;/code&gt; needs a specific format to be used with &lt;code&gt;cl-dbi&lt;/code&gt;, which is the library that I used to interface with the database. In a real application, it would be good to differentiate between &lt;em&gt;dev&lt;/em&gt; and &lt;em&gt;prod&lt;/em&gt; mode with different configurations used, for example to point to different databases or to use a different server with &lt;em&gt;Clack&lt;/em&gt;.&lt;/p&gt;
&lt;h2&gt;Database&lt;/h2&gt;
&lt;p&gt;I created a new file in &lt;code&gt;db/schema.sql&lt;/code&gt; and put the SQL code to create a message table.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;CREATE TABLE message (
    id       INTEGER PRIMARY KEY AUTOINCREMENT,
    username VARCHAR(50) NOT NULL,
    ts       DATETIME NOT NULL,
    content  TEXT NOT NULL
);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then I ran &lt;code&gt;sqlite3 guestbook.sqlite --init db/schema.sql&lt;/code&gt; from the terminal to create and initialise a new database in the project root.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-lisp&quot;&gt;(in-package :cl-user)
(defpackage guestbook.db
  (:use :cl)
  (:import-from :guestbook.config
                :*config*
                :*application-root*))
(in-package :guestbook.db)

(syntax:use-syntax :annot)

(defun connection-settings (&amp;amp;optional (db :maindb))
  (cdr (assoc db (getf *config* :databases))))

@export
(defun db (&amp;amp;optional (db :maindb))
	&amp;quot;Returns a cached database connection for DB (defaults to :maindb). 
  Uses `connection-settings` and `dbi:connect-cached`. 
	
	Usage: (db) or (db :testdb)&amp;quot;
  (apply #&amp;#39;dbi:connect-cached (connection-settings db)))

@export
(defvar *connection* nil)

@export
(defmacro with-connection (conn &amp;amp;body body)
  &amp;quot;Executes BODY with *CONNECTION* dynamically bound to CONN.
CONN should be a database connection object, typically from `db`.

Usage: (with-connection (db :maindb)
         (dbi:do-sql *connection* \&amp;quot;SELECT * FROM users\&amp;quot;))&amp;quot;
  `(let ((*connection* ,conn))
     (unless *connection*
       (error &amp;quot;Database connection cannot be NIL&amp;quot;))
     ,@body))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is the first macro of the project. It’s a simple wrapper that provides a new variable &lt;code&gt;*connection*&lt;/code&gt; to use inside the &lt;code&gt;body&lt;/code&gt;. It raises an error if the &lt;code&gt;conn&lt;/code&gt; value that we passed is not initialised. The function &lt;code&gt;db&lt;/code&gt; instead returns a valid connection, cached automatically by the library.&lt;/p&gt;
&lt;p&gt;Then I defined some functions to perform CRUD operations on the database. &lt;code&gt;format-timestamp&lt;/code&gt; converts a universal timestamp value into a readable date-time string.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-lisp&quot;&gt;(defun format-timestamp (universal-time)
  &amp;quot;Converts a universal time value into a human-readable timestamp string,
formatted as &amp;#39;YYYY-MM-DD HH:MM:SS&amp;#39;.&amp;quot;
  (multiple-value-bind (sec min hour day month year)
      (decode-universal-time universal-time)
    (format nil &amp;quot;~4,&amp;#39;0D-~2,&amp;#39;0D-~2,&amp;#39;0D ~2,&amp;#39;0D:~2,&amp;#39;0D:~2,&amp;#39;0D&amp;quot; year month day hour min sec)))

(defun add-message (name message)
  &amp;quot;Inserts a new message into the database with the given NAME and MESSAGE content.&amp;quot;
  (with-connection (db)
    (let ((sql &amp;quot;INSERT INTO message (username, ts, content) VALUES (?, ?, ?)&amp;quot;)
          (ts (get-universal-time)))
      (dbi:do-sql *connection* sql (list name ts message)))))


(defun delete-message (id)
  &amp;quot;Deletes the message with the given ID from the database.&amp;quot;
  (with-connection (db)
    (let ((sql &amp;quot;DELETE FROM message WHERE id = ?&amp;quot;))
      (dbi:do-sql *connection* sql (list id)))))


(defun get-all-messages ()
  &amp;quot;Retrieves all messages from the database, ordered by timestamp descending.
Timestamps are formatted as human-readable strings.&amp;quot;
  (with-connection (db)
    (let* ((sql &amp;quot;SELECT * FROM message ORDER BY ts DESC&amp;quot;)
           (messages (dbi:fetch-all
                      (dbi:execute
                       (dbi:prepare *connection* sql)))))
      (mapcar (lambda (row)
                (setf (getf row :|ts|) (format-timestamp (getf row :|ts|)))
                row)
              messages))))
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;The Web App&lt;/h2&gt;
&lt;p&gt;Finally we can create the web application which I put inside &lt;code&gt;src/web.lisp&lt;/code&gt;. It’s a bit longer then the other files so I will break it into chunks.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-lisp&quot;&gt;(in-package :cl-user)
(defpackage guestbook.web
  (:use :cl
        :caveman2)
  (:import-from :guestbook.config
                :*template-directory*)
  (:import-from :guestbook.db
                :add-message
                :delete-message
                :get-all-messages)
  (:export :*web*))
(in-package :guestbook.web)

(defclass &amp;lt;web&amp;gt; (&amp;lt;app&amp;gt;) ())
(defvar *web* (make-instance &amp;#39;&amp;lt;web&amp;gt;))
(clear-routing-rules *web*)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The web framework I am using is called &lt;em&gt;Caveman&lt;/em&gt;, developed by &lt;a href=&quot;https://github.com/fukamachi&quot;&gt;Eitaro Fukamachi&lt;/a&gt;, who is a very prolific &lt;em&gt;lisper&lt;/em&gt; and the author of multiple libraries that I am using, including &lt;em&gt;Lack&lt;/em&gt;, &lt;em&gt;Clack&lt;/em&gt;, and &lt;em&gt;cl-dbi&lt;/em&gt;, all having great integration with each other. &lt;code&gt;&amp;lt;app&amp;gt;&lt;/code&gt; is a &lt;em&gt;class&lt;/em&gt; defined by the web framework, and I am extending it and instantiating it in &lt;code&gt;*web*&lt;/code&gt;. &lt;code&gt;clear-routing-rules&lt;/code&gt; is a function inherited from &lt;em&gt;Ningle&lt;/em&gt;, another web framework, which clears the route associations inside the web app instance.&lt;/p&gt;
&lt;h3&gt;Templates&lt;/h3&gt;
&lt;p&gt;Our web app needs to render some static templates with data, and to do that there’s a great library called &lt;code&gt;djula&lt;/code&gt;, which allows us to use most of the same tags and filters that &lt;a href=&quot;https://docs.djangoproject.com/en/5.1/ref/templates/builtins/&quot;&gt;Django exposes&lt;/a&gt; in its template engine.&lt;/p&gt;
&lt;p&gt;I’m not going to include the templates source here for space reasons, in the repository they&amp;#39;re in the &lt;code&gt;templates/&lt;/code&gt; folder.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-lisp&quot;&gt;(djula:add-template-directory *template-directory*)

(defun render (template-path &amp;amp;optional env)
  &amp;quot;Renders a Djula template from TEMPLATE-PATH.
ENV is an optional plist of variables passed to the template.&amp;quot;
  (apply #&amp;#39;djula:render-template*
         (djula:compile-template* (princ-to-string template-path))
         nil
         env))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first function call tells &lt;code&gt;djula&lt;/code&gt; where to find the templates in the project. &lt;code&gt;render&lt;/code&gt; is a function that receives a template path as a parameter and compiles the template for better performance.&lt;/p&gt;
&lt;h3&gt;Routes&lt;/h3&gt;
&lt;p&gt;To allow users to perform CRUD operations, we need to expose a few routes to be called by the web frontend. There are two ways to define routes in Caveman, but this one seems a bit clearer to me than using annotations. &lt;code&gt;defroute&lt;/code&gt; is a macro that receives the route path, some parameters like &lt;code&gt;:method&lt;/code&gt; and eventually some arguments, and then defines the body to handle the request. Inside the body, we can access the request object via &lt;code&gt;*request*&lt;/code&gt; and extract data from it using, for example, the function &lt;code&gt;request-body-parameters&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The routes are self-descriptive. &lt;code&gt;/&lt;/code&gt; renders &lt;code&gt;index.html&lt;/code&gt;, passing all the messages from the db; &lt;code&gt;/message&lt;/code&gt; handles POST requests and inserts the message in the database if the parameters conform; and &lt;code&gt;/message/delete&lt;/code&gt; deletes a message. &lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-lisp&quot;&gt;(defroute &amp;quot;/&amp;quot; ()
  (render #P&amp;quot;index.html&amp;quot;
          (list :messages (get-all-messages))))


(defroute (&amp;quot;/message&amp;quot; :method :POST) ()
  (let* ((body-params (request-body-parameters *request*))
         (name-param (assoc &amp;quot;name&amp;quot; body-params :test #&amp;#39;string=))
         (message-param (assoc &amp;quot;message&amp;quot; body-params :test #&amp;#39;string=)))
    (if (and (consp name-param) (consp message-param))
      (add-message (cdr name-param)
                   (cdr message-param))
      (format t &amp;quot;Missing body parameters: received ~A~%&amp;quot; body-params)))
  (redirect &amp;quot;/&amp;quot;))


(defroute (&amp;quot;/message/delete&amp;quot; :method :POST) ()
  (let* ((body-params (request-body-parameters *request*))
         (id-param (assoc &amp;quot;id&amp;quot; body-params :test #&amp;#39;string=)))
    (if (consp id-param)
        (let ((id (ignore-errors (parse-integer (cdr id-param)))))
          (when id
            (delete-message id)))
        (format t &amp;quot;Missing id parameter.&amp;quot;)))
  (redirect &amp;quot;/&amp;quot;))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I also added another function, which defines a method on the web app class. &lt;code&gt;on-exception&lt;/code&gt; is a generic function called when an exception occurs in the web application. This method is specific on the parameter type, since it will run only if the exception has code 404 — not found — and in that case I return a specific custom template.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-lisp&quot;&gt;(defmethod on-exception ((app &amp;lt;web&amp;gt;) (code (eql 404)))
  (declare (ignore app code))
  (render #P&amp;quot;404.html&amp;quot;))
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Run the demo&lt;/h2&gt;
&lt;p&gt;Now I can load the project into the environment with Quicklisp.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-lisp&quot;&gt;&amp;gt; (ql:quickload :guestbook)
To load &amp;quot;guestbook&amp;quot;:
  Load 1 ASDF system:
    guestbook
; Loading &amp;quot;guestbook&amp;quot;
......................
(:GUESTBOOK)
CL-USER&amp;gt; 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then I can start the server and point my browser to &lt;code&gt;127.0.0.1:3210&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-lisp&quot;&gt;&amp;gt; (guestbook.core:start)
Hunchentoot server is started.
Listening on 127.0.0.1:3210.
Server started
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;/assets/img/guestbook.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;I can send messages that get saved with a timestamp and then delete them. Pretty simple.&lt;/p&gt;
&lt;h2&gt;Reducing boilerplate&lt;/h2&gt;
&lt;p&gt;Lisp became popular for a series of reasons, and one of the most cited is its ability to reduce boilerplate thanks to the metaprogramming capabilities of the language. Lisp hackers are proud of being able to code solutions faster and do exploratory programming, reducing the size of the code they need to write to reach a solution.&lt;/p&gt;
&lt;p&gt;When comparing the lines-of-code count of my Common Lisp guestbook against the Python-Flask version, the latter seems quicker and simpler to write — 36 lines of Python vs. 229 of Lisp. Lisp’s strength is its ability to model itself according to the problem the developer is solving. In this case, I am dealing with a simple guestbook demo, so it may not be strictly necessary, but to present the language better I will try to reduce the size of the program by hiding some code and configuration.&lt;/p&gt;
&lt;p&gt;First, let’s have a look at the new guestbook app, written in my new custom web framework called &lt;em&gt;flashcl&lt;/em&gt;: 29 LOC, properly formatted and stripped of all comments, and not too hard to read.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-lisp&quot;&gt;(in-package :cl-user)
(defpackage guestbook.core
  (:use :cl :flashcl))
(in-package :guestbook.core)

(init-flashcl :sqlite3 &amp;quot;guestbook.sqlite&amp;quot;)

(defmodel message
  ((username :col-type (:varchar 50) :accessor message-username)
   (content  :col-type  :text        :accessor message-content)))

(defroute &amp;quot;/&amp;quot; ()
  (render #P&amp;quot;index.html&amp;quot; (list :messages (db-all &amp;#39;message))))

(defroute (&amp;quot;/message&amp;quot; :method :POST) ()
  (let ((name (form-param &amp;quot;name&amp;quot;))
        (message (form-param &amp;quot;message&amp;quot;)))
    (if (and name message (&amp;gt; (length name) 0) (&amp;gt; (length message) 0))
      (db-add (make-instance &amp;#39;message :username name :content message))
      (format t &amp;quot;Missing body parameters: received ~A~%&amp;quot; (body-params))))
  (redirect &amp;quot;/&amp;quot;))

(defroute (&amp;quot;/message/delete/:id&amp;quot; :method :POST) (&amp;amp;key id)
  (if id
    (let ((id (ignore-errors (parse-integer id))))
      (when id
        (db-delete (db-find &amp;#39;message id)))
      (format t &amp;quot;Missing id parameter.&amp;quot;)))
  (redirect &amp;quot;/&amp;quot;))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Where did &lt;code&gt;start&lt;/code&gt; go? It is now part of the &lt;em&gt;flashcl&lt;/em&gt; framework, so it’s imported in the package. Here’s the usage reference.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-lisp&quot;&gt;;; --- Run the Application ---
;; Call run-app function from your REPL or add it here to run on load.
;; Call stop-app to stop the server.
;;
;; Example: (guestook::run-app) or just (run-app) inside the package.
;; (run-app :port 5000 :server :hunchentoot)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then I slightly modified the template delete button to point to the correct route with the &lt;code&gt;id&lt;/code&gt; parameter.&lt;/p&gt;
&lt;p&gt;I&amp;#39;m going to show just some the new code that I added to write &lt;em&gt;flashcl&lt;/em&gt;. I mostly merged the old code in a new file trying to make it as reusable as I could for other web projects, since it&amp;#39;s possible to define new database models and routes quickly, with support for static files and templates. I used &lt;em&gt;mito&lt;/em&gt;, another library from &lt;a href=&quot;https://github.com/fukamachi/mito&quot;&gt;Eitaro Fukamachi&lt;/a&gt;, which is an ORM that works well with SQLite.&lt;/p&gt;
&lt;p&gt;First I imported the library and exported only what’s needed by the user.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-lisp&quot;&gt;(defpackage :flashcl
  (:use #:cl)
  (:import-from #:caveman2
                #:defroute
                #:redirect
                #:*request*
                #:*response*)
  (:import-from #:lack.request
                #:request-parameters)
  (:import-from #:mito
                #:dao-table-class ; Re-export metaclass for use in defmodel
                #:connect-toplevel
                #:ensure-table-exists
                #:select-dao
                #:find-dao
                #:delete-dao
                #:insert-dao)
  (:export ;; Setup
          #:init-flashcl
          ;; App Definition
          #:flashcl-app ;; Variable holding the app instance
          #:defmodel
          ;; Routing &amp;amp; Request/Response
          #:defroute
          #:form-param
          #:render ;; Re-export caveman&amp;#39;s render (or wrap it)
          #:redirect ;; Re-export caveman&amp;#39;s redirect
          ;; Database
          #:db-all
          #:db-add
          #:db-find
          #:db-delete
          #:dao-table-class ;; Re-export metaclass
          ;; Running
          #:run-app
          #:stop-app))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then I wrote an initialisation function similar to Flask’s, which sets various variables and creates a new instance of the Caveman webapp.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-lisp&quot;&gt;(defun init-flashcl (db-type db-path &amp;amp;optional (template-dir &amp;quot;templates&amp;quot;)
                                               (static-dir &amp;quot;static&amp;quot;))
  &amp;quot;Initializes Flashcl environment. Sets DB/Template paths, connects DB.&amp;quot;
  (setf *database-path* (get-absolute-path db-path))
  (setf *static-directory* (get-absolute-path static-dir))

  ;; Set Djula&amp;#39;s template directory
  (djula:add-template-directory (get-absolute-path template-dir))
  (format t &amp;quot;Set template directory as ~A~%&amp;quot; (get-absolute-path template-dir))

  ;; Connect to SQLite database
  (handler-case (connect-toplevel db-type :database-name *database-path*)
    (error (c)
      (format *error-output* &amp;quot;~&amp;amp;Error connecting to database ~A: ~A~%&amp;quot; *database-path* c)))

  ;; Define the Caveman2 app instance here
  (setf flashcl-app (make-instance &amp;#39;caveman2:&amp;lt;app&amp;gt;)))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To make it easy to define a new database model for the application, hiding the &lt;em&gt;mito&lt;/em&gt; library, I created a macro that ensures the table gets created correctly. &lt;em&gt;mito&lt;/em&gt; automatically adds a few fields to the table definition, like &lt;code&gt;id&lt;/code&gt; and &lt;code&gt;created_at&lt;/code&gt; or &lt;code&gt;updated_at&lt;/code&gt;, so we don&amp;#39;t have to worry about them.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-lisp&quot;&gt;(defmacro defmodel (name slots &amp;amp;rest options)
  &amp;quot;Defines a Mito DAO class and ensures its table exists.
   Example: (flashcl:defmodel comment
              ((name :col-type (:varchar 20))
               (comment :col-type :text)))&amp;quot;
  (let ((class-options options)
        (table-name (string-downcase name))) ; Use singular name by default
    
    ;; Add table name inference if not present
    (unless (find :table-name options :key #&amp;#39;car)
      (push `(:table-name ,table-name) class-options))

    `(progn
      (defclass ,name ()
        ,slots
        (:metaclass mito:dao-table-class)
        ,@class-options)
      ;; Ensure table exists after class definition
      ;; Note: This runs at compile/load time when defmodel is processed.
      ;; Ensure DB is connected before loading code using defmodel.
      (handler-case (ensure-table-exists &amp;#39;,name)
        (error (c)
          (format *error-output* &amp;quot;~&amp;amp;Warning: Could not ensure table for ~A (DB might not be connected yet?): ~A~%&amp;quot; &amp;#39;,name c)))
      ;; Return the class name
      &amp;#39;,name)))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then I added some database helpers to perform a few CRUD actions on the db.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-lisp&quot;&gt;(defun db-all (class-name)
  &amp;quot;Selects all records for the given model class.&amp;quot;
  (select-dao class-name))

(defun db-find (class-name id)
  &amp;quot;Finds a model instance by ID.&amp;quot;
  (find-dao class-name :id id))

(defun db-add (instance)
  &amp;quot;Inserts a model instance into the database.&amp;quot;
  (insert-dao instance))

(defun db-delete (instance)
  &amp;quot;Deletes a model instance from the database.&amp;quot;
  (delete-dao instance))
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;To recap, in this tutorial I used some of the latest libraries in Common Lisp to create a simple guestbook webapp. Then I wrote a simple reusable wrapper to make our code more concise, aiming to challenge the Flask framework in Python. The full source code of the two versions it&amp;#39;s &lt;a href=&quot;https://github.com/eliascotto/cl-guestbook&quot;&gt;here&lt;/a&gt; and &lt;a href=&quot;https://github.com/eliascotto/cl-guestbook-v2&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Ultimately I would like to give my opinion on using Common Lisp to write a web server. 
Common Lisp shines when dealing with low-level tasks like &lt;a href=&quot;https://blog.funcall.org/lisp%20psychoacoustics/2024/05/01/worlds-loudest-lisp-program/&quot;&gt;small systems programming&lt;/a&gt; or performing &lt;a href=&quot;https://www.grammarly.com/blog/engineering/running-lisp-in-production/&quot;&gt;intensive computation&lt;/a&gt; at scale. When these complex systems need to communicate with the outside world, perhaps via an API, writing a server is the correct way and Common Lisp is capable of delivering that.&lt;/p&gt;
&lt;p&gt;But despite the fact that the language is easily adaptable and comes with performant server libraries (Hunchentoot and Woo), I would say that there are better alternatives for developing generic modern web apps. Hot reloading is now a feature present in many web frameworks, and Common Lisp is not really shining for being ergonomic, nor does it come with many built-ins. Clojure, by contrast, is a modern Lisp dialect with great web frameworks, nice documentation and tons of stable libraries. I would definitely choose the latter for a fresh web project, since with CL I get the feeling that I would end up having to write more code than I should to add custom features and middlewares.&lt;/p&gt;
&lt;p&gt;I would like to give a shout-out to &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=rheller.alive&quot;&gt;Alive&lt;/a&gt;, which is the only Common Lisp extension for VSCode that implements the REPL with features similar to what SLIME and SLY bring to Emacs. The extension is still under development and not yet a full replacement for Emacs, especially during debugging, but it has great features and a lot of potential to introduce Common Lisp to newcomers, thanks to the VSCode web interface.&lt;/p&gt;
&lt;p&gt;Feel free to email me if you have any questions, recommendations, or even complaints.&lt;/p&gt;
</content:encoded></item><item><title>Rust 101</title><link>https://scotto.me/blog/2024-04-10-rust-101/</link><guid isPermaLink="true">https://scotto.me/blog/2024-04-10-rust-101/</guid><description>Rust 101</description><pubDate>Wed, 10 Apr 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I’ve recently had the chance to try Rust for a project and it has been a surprising pleasant experience. Rust is a modern language and I felt quire familiar with it in a few days. It has a simple and effective design and thanks to that, it gets frequently mentioned as a successor to old low level languages C like. Rust is &lt;em&gt;fast&lt;/em&gt; and, in a lot of benchmarks, the compiled code performance is comparable to C and C++. I don’t have experience yet with other similar low-level languages as &lt;em&gt;&lt;a href=&quot;https://nim-lang.org/&quot;&gt;Nim&lt;/a&gt;&lt;/em&gt; or &lt;em&gt;&lt;a href=&quot;https://ziglang.org/&quot;&gt;Zig&lt;/a&gt;&lt;/em&gt; but I believe that there’s a reason why Rust got extremely &lt;a href=&quot;https://survey.stackoverflow.co/2023/#section-admired-and-desired-programming-scripting-and-markup-languages&quot;&gt;popular&lt;/a&gt; in the last few years.&lt;/p&gt;
&lt;p&gt;In this article I’ll write down a quick overview of the most important concept that I found make Rust a different and more evolved language compared to it’s predecessor. The Rust &lt;a href=&quot;https://doc.rust-lang.org/book/&quot;&gt;documentation&lt;/a&gt; is really well written with a lot of example and it will allow you to use the language in a very short time.&lt;/p&gt;
&lt;h2&gt;Memory Safety&lt;/h2&gt;
&lt;p&gt;Rust is a memory &lt;em&gt;safe&lt;/em&gt; language which means that it’s design prevent the programmer to do operation that could provoke memory faults and crashes of the program. If you ever wrote C or C++ you know what kind of bugs I’m talking about. This kind of problems are hard to spot and debug and in complex programs, it gets easy to use an already free memory or to forget to free one.&lt;/p&gt;
&lt;p&gt;There have been two main ways to manage program memory. One is letting the memory management in the hands of the programmer (as C, C++), and the other is using a Garbage Collector that will clean the unused allocated memory portions for you (as Lisp, Java, Python, JS). Manually freeing the memory can get complicated with large and complex programs, and automatic garbage collection can slow down your execution at random, and it’s not that easy to control. &lt;/p&gt;
&lt;p&gt;Rust bring a different approach; writing programs that are actually memory safe by design. It does that by not exposing the memory management functions, without using an external tool to do the job. It introduces the concept of &lt;em&gt;ownership&lt;/em&gt;, a set of rules that check your code at &lt;em&gt;compile time&lt;/em&gt; to prevent you to do  operations that break the ownership of a variable.&lt;/p&gt;
&lt;h3&gt;Ownership&lt;/h3&gt;
&lt;p&gt;This are the ownership rules:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Each value in Rust has an &lt;em&gt;owner&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;There can only be one owner at a time.&lt;/li&gt;
&lt;li&gt;When the owner goes out of scope, the value will be &lt;em&gt;dropped&lt;/em&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;let s1 = String::from(&amp;quot;hello&amp;quot;); // s1 is the owner of the String
let s2 = s1; // s2 becomes the new owner, and s1 is invalidated
println!(&amp;quot;{}, world!&amp;quot;, s1); // This will cause a compile-time error because s1 is no longer valid
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The previous code will not compile. The compiler would even give you suggestion to what caused the error: &lt;code&gt;error[E0382]: borrow of moved value: s1&lt;/code&gt;. One may think that the string s1 should still be there, but in reality Rust already called &lt;code&gt;drop&lt;/code&gt; on the string structure, deallocating the memory segment and making it no longer valid.&lt;/p&gt;
&lt;p&gt;Rust is getting in the way of the programmer for a good reasons; following this rules will prevent problems with memory deallocation, like forgetting to deallocate something, accessing a resource already deallocated, or double freeing a variable. In exchange, Rust is enforcing some patterns and providing some data structure to solve all ownership problems. The following is a useful schema I found on reddit, that quickly points you to which data structure is better to use for each scenario (&lt;code&gt;T&lt;/code&gt; is the generic data type).&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/img/nhhxzcwqd6q61.png&quot; alt=&quot;rust ownership diagram&quot; title=&quot;source: https://www.reddit.com/r/rust/comments/mgh9n9/ownership_concept_diagram/&quot;&gt;&lt;/p&gt;
&lt;h3&gt;Borrowing&lt;/h3&gt;
&lt;p&gt;Borrowing is a mechanism that allows you to create references to data owned by another variable, enabling multiple parts of your code to access and potentially modify the same data without transferring ownership.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;fn main() {
    let mut s = String::from(&amp;quot;hello&amp;quot;);

    change(&amp;amp;mut s);
}

fn change(some_string: &amp;amp;mut String) {
    some_string.push_str(&amp;quot;, world&amp;quot;);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the code above, I&amp;#39;ve just created an &lt;em&gt;mutable reference&lt;/em&gt; to a &lt;code&gt;String&lt;/code&gt; object, and passed it to a function that modify the string. This behaviour it&amp;#39;s called borrowing, since we &lt;em&gt;borrow&lt;/em&gt; the value, and then give it back to the caller when finished using it.&lt;/p&gt;
&lt;p&gt;In Rust, we cannot borrow as &lt;em&gt;mutable&lt;/em&gt; variable more than once. This restriction of preventing multiple mutable references to the same data, helps preventing &lt;a href=&quot;https://en.wikipedia.org/wiki/Race_condition#Data_race&quot;&gt;&lt;em&gt;data races&lt;/em&gt;&lt;/a&gt; at compile time.&lt;/p&gt;
&lt;h2&gt;Structs and objects&lt;/h2&gt;
&lt;p&gt;Rust allows the creation of custom data types using &lt;code&gt;struct&lt;/code&gt; and &lt;code&gt;enum&lt;/code&gt;. A struct is between a C &lt;em&gt;struct&lt;/em&gt; and a C++ &lt;em&gt;class&lt;/em&gt;. It can be used as object and have access to &lt;code&gt;self&lt;/code&gt;, but it’s missing a full support for &lt;em&gt;inheritance&lt;/em&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;struct Rectangle {
    width: u32,
    height: u32,
}

impl Rectangle {
    fn new(w: u32, h: u32) -&amp;gt; Rectangle {
        Rectangle {
            width: w,
            height: h,
        }
    }

    fn area(&amp;amp;self) -&amp;gt; f64 {
        (self.width * self.height) as f64
    }
}

fn main() {
    let mut rect = Rectangle::new(3, 4);
    println!(&amp;quot;Area: {}&amp;quot;, rect.area());
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A new struct &lt;code&gt;Rectangle&lt;/code&gt; has been defined, with a simple &lt;code&gt;area&lt;/code&gt; method which access the property using the reference to itself.&lt;/p&gt;
&lt;p&gt;When a new struct is defined inside a file, it can be &lt;em&gt;encapsulated&lt;/em&gt; simply by avoiding the use of &lt;code&gt;pub&lt;/code&gt; on the methods. This way, they will not be visible from outside but still accessible from inside.&lt;/p&gt;
&lt;h3&gt;Traits&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Polymorphism&lt;/em&gt; can be pefrormed by defining a &lt;code&gt;Trait&lt;/code&gt; which adds the possibility to have shared behaviour between structures. &lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;trait Area {
    fn area(&amp;amp;self) -&amp;gt; f64;
}

impl Area for Circle {
    fn area(&amp;amp;self) -&amp;gt; f64 {
        std::f64::consts::PI * self.radius * self.radius
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here I&amp;#39;ve defined a trait &lt;code&gt;Area&lt;/code&gt; which every shape struct can implement in it’s own way. The trait it’s only the function signature, with parameters and expected return type.&lt;/p&gt;
&lt;h3&gt;Enum&lt;/h3&gt;
&lt;p&gt;Enum are just a way of define a set of values that a variable of that type can take. It’s similar to &lt;code&gt;struct&lt;/code&gt; in the sense that accept the use of &lt;code&gt;impl&lt;/code&gt; with custom methods and traits.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;enum Animal {
    Bird,
    Insect,
    Fish,
    Mammal,
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Pattern matching&lt;/h2&gt;
&lt;p&gt;Pattern matching is a construct that is essential in the Rust design. It allows to automatically match the value of a variable using it’s possible states, similar to the statement &lt;code&gt;case&lt;/code&gt; in other languages. I use the operator &lt;code&gt;match&lt;/code&gt; that receives the variable and give the possibility to execute code when a value is matching.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;impl Animal {
    fn can_fly(&amp;amp;self) -&amp;gt; bool {
        match self {
            Animal::Bird =&amp;gt; true,
            Animal::Insect =&amp;gt; true,
            _ =&amp;gt; false, // Covers Fish and Mammal
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For example, here it&amp;#39;s matching all the possible states that a variable of type &lt;code&gt;Animal&lt;/code&gt; can have. The option &lt;code&gt;_&lt;/code&gt; is a catch-all pattern, representing all the other possible states that the variable can take.&lt;/p&gt;
&lt;h2&gt;Result and Option&lt;/h2&gt;
&lt;p&gt;Two enumerated types that are part of the Rust standard library are &lt;code&gt;Result&lt;/code&gt; and &lt;code&gt;Option&lt;/code&gt;. They’re values used to deal with errors that need to be managed and potentially absent values. To access the value, the pattern matching method shown above is required.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Result&lt;/code&gt; is used in case a function may fail and there&amp;#39;s a need to grab the exception and handle it. Rust allows functions to throw errors and then catch them from the caller by performing a &lt;code&gt;match&lt;/code&gt; on the function&amp;#39;s returned value.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;use std::fs::File;
use std::io;

fn read_file(path: &amp;amp;str) -&amp;gt; Result&amp;lt;String, io::Error&amp;gt; {
    let file = File::open(path)?;
    let mut contents = String::new();
    file.read_to_string(&amp;amp;mut contents)?;
    Ok(contents)
}

fn main() {
    match read_file(&amp;quot;example.txt&amp;quot;) {
        Ok(contents) =&amp;gt; println!(&amp;quot;File contents: {}&amp;quot;, contents),
        Err(error) =&amp;gt; println!(&amp;quot;Error reading file: {}&amp;quot;, error),
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;?&lt;/code&gt; is a special operator in Rust that allows to return the error directly, saving you the boilerplate of writing another match.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Option&lt;/code&gt; instead is used to return an optional value, since Rust doesn’t have the concept of &lt;code&gt;null&lt;/code&gt; (and no Null Pointer Exception).&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;fn find_first_even(numbers: &amp;amp;[i32]) -&amp;gt; Option&amp;lt;i32&amp;gt; {
    for num in numbers {
        if num % 2 == 0 {
            return Some(*num);
        }
    }
    None
}

fn main() {
    let numbers = vec![1, 3, 5, 7, 8];
    match find_first_even(&amp;amp;numbers) {
        Some(even) =&amp;gt; println!(&amp;quot;First even number: {}&amp;quot;, even),
        None =&amp;gt; println!(&amp;quot;No even numbers found&amp;quot;),
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Functional&lt;/h2&gt;
&lt;p&gt;Rust took &lt;em&gt;closures&lt;/em&gt; and &lt;em&gt;iterators&lt;/em&gt; from functional programming. It&amp;#39;s easy to write inline functions and iterate over array with the set of functions available for functional programming.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;let numbers = vec![1, 2, 3, 4, 5];
let doubled: Vec&amp;lt;_&amp;gt; = numbers.iter().map(|x| { x * 2 }).collect();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the code above I&amp;#39;m using &lt;code&gt;map&lt;/code&gt; over a list of numbers, and running the lambda function &lt;code&gt;|x| x * 2&lt;/code&gt; on it, in fact creating a closure. If you need to add the possibility to add iteraction support to a struct, you would need to implement the &lt;code&gt;Iterator&lt;/code&gt; trait, as shown &lt;a href=&quot;https://doc.rust-lang.org/rust-by-example/trait/iter.html&quot;&gt;in the docs&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Analyzer&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/rust-lang/rust-analyzer&quot;&gt;rust-analyzer&lt;/a&gt; is what is going to help you understanding Rust and the patterns that the language is guiding you to use. When integrated inside your favourite editor (I’m using &lt;a href=&quot;https://zed.dev/&quot;&gt;Zed&lt;/a&gt; right now), you will see warning and errors generated directly when saving a file.&lt;/p&gt;
&lt;p&gt;Let’s try to analyse some broken code&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;fn main() {
    let s1 = String::from(&amp;quot;hello&amp;quot;);
    let s2 = s1;
    println!(&amp;quot;{}&amp;quot;, s1);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Why is this code broken?&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;error[E0382]: borrow of moved value: `s1`
  --&amp;gt; src/main.rs:4:20
   |
65 |     let s1 = String::from(&amp;quot;hello&amp;quot;);
   |         -- move occurs because `s1` has type `String`, which does not implement the `Copy` trait
66 |     let s2 = s1;
   |              -- value moved here
67 |     println!(&amp;quot;{}&amp;quot;, s1);
   |                    ^^ value borrowed here after move
   |
   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider cloning the value if the performance cost is acceptable
   |
66 |     let s2 = s1.clone();
   |                ++++++++
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Rust is telling that when the code does &lt;code&gt;s2 = s1&lt;/code&gt;, it moves the value &lt;code&gt;s1&lt;/code&gt; so it cannot be used anymore in the &lt;code&gt;println&lt;/code&gt; call. A solution is to &lt;em&gt;clone&lt;/em&gt; &lt;code&gt;s1&lt;/code&gt; into &lt;code&gt;s2&lt;/code&gt; so it will then have two independent instances of the string. Pretty handy to find a quick solution, especially for beginners. The Rust team did a great job for creating high quality error messages to guide the user to find a solution.&lt;/p&gt;
&lt;h2&gt;Macros&lt;/h2&gt;
&lt;p&gt;Rust supports different types of macros: &lt;em&gt;declarative&lt;/em&gt; and &lt;em&gt;procedural&lt;/em&gt;. Macro helps extending the language by removing boilerplate code and even extending programs with external code (e.g. plugins).&lt;/p&gt;
&lt;p&gt;Declarative macros are called like functions, they just append &lt;code&gt;!&lt;/code&gt; to their name.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;#[macro_export]
macro_rules! vec {
    ( $( $x:expr ),* ) =&amp;gt; {
        {
            let mut temp_vec = Vec::new();
            $(
                temp_vec.push($x);
            )*
            temp_vec
        }
    };
}

let v = vec![1, 2, 3, 4]; // Creates a new vec inline
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;My suggestion is to avoid using macros and always prefer functions where possible. Macros are hard to understand, maintain and document when they get complex.&lt;/p&gt;
&lt;h2&gt;Cargo and packages&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;cargo&lt;/code&gt; is the official package manager for Rust. It downloads the dependencies and keep track of the Rust version the project is supporting. It can be used for all the task related to the project, like running, building it, generating the documentations, etc. The package registry is &lt;a href=&quot;https://crates.io/&quot;&gt;crates.io&lt;/a&gt; which counts more than 140K packages as today.&lt;/p&gt;
&lt;h2&gt;Tests&lt;/h2&gt;
&lt;p&gt;Rust provides a test framework directly in the language which supports both &lt;em&gt;unit&lt;/em&gt; and &lt;em&gt;integration&lt;/em&gt; tests. &lt;code&gt;cargo test&lt;/code&gt; is how to run all the tests for a project.&lt;/p&gt;
&lt;p&gt;This is a unit test example, included in the same file of the function implementation.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
        let result = 2 + 2;
        assert_eq!(result, 4);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;When to use Rust&lt;/h2&gt;
&lt;p&gt;Rust got really popular in the last few years, but it&amp;#39;s not a solution for all coding problems, nor a suitable alternative for all cases. When performance is a requirement, instead of using C or C++, Rust can provide much nicer usability and ergonomics, since it&amp;#39;s nearly as fast as C but definitely safer, and the choice will pay off in the long run. &lt;a href=&quot;https://discord.com/blog/why-discord-is-switching-from-go-to-rust&quot;&gt;Big companies&lt;/a&gt; have started adopting Rust effectively with great results and enough performance gains in critical parts of their applications to justify the choice.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/img/u80ujhbe23rc1.png&quot; alt=&quot;rust nation uk&quot; title=&quot;Rust Nation UK on Youtube&quot;&gt;&lt;/p&gt;
</content:encoded></item><item><title>Common Lisp data structures</title><link>https://scotto.me/blog/2023-12-12-common-lisp-data-structures/</link><guid isPermaLink="true">https://scotto.me/blog/2023-12-12-common-lisp-data-structures/</guid><description>Common Lisp data structures</description><pubDate>Tue, 12 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Quick reference for the main data structures in Common Lisp. The code has been tested using &lt;em&gt;SBCL&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Some good rules for Common Lisp that I found say:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Use the appropriate data structure for the situation.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Favor iteration over recursion. Recursion is good for recursive data structures.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;List&lt;/h2&gt;
&lt;p&gt;Lists are used when you need to store a &lt;em&gt;sequence&lt;/em&gt; of elements. It supports different data types. They are particularly useful when you need to perform operations that involve recursion or iteration. &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Key points&lt;/strong&gt;: ordered, flexible size, efficient for traversal, slow for random access&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-lisp&quot;&gt;;; Declaration
cl-user&amp;gt; (defparameter *list* &amp;#39;(1 2 3 4))
*list*
cl-user&amp;gt; (list 1 2 3 4) ; alternative
(1 2 3 4)

;; Access
cl-user&amp;gt; (nth 3 *list*) ; not performant for long lists
4 (3 bits, #x4, #o4, #b100)
cl-user&amp;gt; (first *list*)
1 (1 bit, #x1, #o1, #b1)

;; Adding
cl-user&amp;gt; (push &amp;#39;0 *list*)
(0 1 2 3 4)

;; Deleting
cl-user&amp;gt; (setf *list* (remove 1 *list*))
(0 2 3 4)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Association list - alist&lt;/h2&gt;
&lt;p&gt;Association lists are lists, implemented using cons cells, which are used to store key-value pairs where the key is a symbol. They are slower than hash-tables for large amount of data.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Key points&lt;/strong&gt;: key-value pairs, simple structure, inefficient for large datasets&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-lisp&quot;&gt;;; Declaration
cl-user&amp;gt; (defparameter *alist* &amp;#39;((:a . 1) (:b . 2)))
*alist*

;; Access
cl-user&amp;gt; (assoc :a *alist*)
(A . 1)
cl-user&amp;gt; (cdr (assoc :a *alist*))
1

;; Adding
cl-user&amp;gt; (push &amp;#39;(:c . 3) *alist*)
((C . 3) (A . 1) (B . 2))

;; Deleting
cl-user&amp;gt; (setf *alist* (remove :c *alist* :key #&amp;#39;car))
((A . 1) (B . 2))
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Property list - plist&lt;/h2&gt;
&lt;p&gt;Property are used when you need to store key-value pairs and the keys are symbols. They are simpler than hash tables and association lists but can be slower for large amounts of data.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Key points&lt;/strong&gt;: key-value pairs, lightweight, inefficient for large datasets&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-lisp&quot;&gt;;; Declaration
cl-user&amp;gt; (defparameter *plist* &amp;#39;(:key1 value1 :key2 value2))
*plist*

;; Access
cl-user&amp;gt; (getf *plist* :key1)
value1

;; Adding
cl-user&amp;gt; (setf (getf *plist* :new-key) &amp;#39;new-value)
new-value

;; Deleting
cl-user&amp;gt; (remf *plist* :key1)
t
cl-user&amp;gt; *plist*
(:new-key new-value :key2 value2)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Hash table&lt;/h2&gt;
&lt;p&gt;Hash tables store key-value pairs and provide efficient lookup and storage. They are highly efficient for large datasets.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Key points&lt;/strong&gt;: key-value pairs, fast lookups, mutable&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-lisp&quot;&gt;;; Declaration
cl-user&amp;gt; (defparameter *hash-table* (make-hash-table))
*hash-table*

;; Adding
cl-user&amp;gt; (setf (gethash &amp;#39;key1 *hash-table*) &amp;#39;value1)
value1

;; Access
cl-user&amp;gt; (gethash &amp;#39;key1 *hash-table*)
value1

;; Deleting
cl-user&amp;gt; (remhash &amp;#39;key1 *hash-table*)
t
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Array&lt;/h2&gt;
&lt;p&gt;Arrays are multidimensional data structures that hold elements accessible by indices. Arrays are faster than lists for random access, but slower for operations that involve adding or removing elements. Arrays have a fixed size upon creation, but they can be resized using &lt;code&gt;adjust-array&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Key points&lt;/strong&gt;: multidimensional, fixed size, efficient access by index&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-lisp&quot;&gt;;; Declaration
cl-user&amp;gt; (defparameter *array* (make-array 4 :initial-contents &amp;#39;(1 2 3 4)))
*array*

;; Access
cl-user&amp;gt; (aref *array* 2)
3

;; Modifying
cl-user&amp;gt; (setf (aref *array* 1) 5)
5

;; Extending/Shrinking
cl-user&amp;gt; (setf *array* (adjust-array *array* 6 :initial-element 0))
#(1 5 3 4 0 0)

;; Deleting
;; To delete elements, consider creating a new array without the unwanted elements.
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Vector&lt;/h2&gt;
&lt;p&gt;A vector is a one-dimensional array. Vectors are similar to arrays but can dynamically grow and shrink using functions like &lt;code&gt;vector-push&lt;/code&gt; and &lt;code&gt;vector-pop&lt;/code&gt;. Vectors are particularly useful when you need a sequence that can change size dynamically.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Key points&lt;/strong&gt;: one-dimensional, dynamic size, efficient access by index&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-lisp&quot;&gt;;; Declaration
cl-user&amp;gt; (defparameter *vector* #(1 2 3 4))
*vector*

;; Access
cl-user&amp;gt; (elt *vector* 0)
1

;; Modifying
cl-user&amp;gt; (setf (elt *vector* 3) 5)
5

;; Adding elements
cl-user&amp;gt; (vector-push-extend 6 *vector*)
4
cl-user&amp;gt; *vector*
#(1 2 3 5 6)

;; Removing elements
cl-user&amp;gt; (vector-pop *vector*)
6
cl-user&amp;gt; *vector*
#(1 2 3 5)

;; Converting to a list
cl-user&amp;gt; (coerce *vector* &amp;#39;list)
(1 2 3 5)

;; Shrinking/Extending
cl-user&amp;gt; (setf (fill-pointer *vector*) 2)
2
cl-user&amp;gt; *vector*
#(1 2)

;; Push extending
cl-user&amp;gt; (vector-push-extend 7 *vector*)
2
cl-user&amp;gt; *vector*
#(1 2 7)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Structure&lt;/h2&gt;
&lt;p&gt;Structures are user-defined data structures created using &lt;code&gt;defstruct&lt;/code&gt;, allowing the grouping of different data types together.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Key points&lt;/strong&gt;: user-defined, structured, efficient access&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-lisp&quot;&gt;;; Declaration
cl-user&amp;gt; (defstruct person name age)
person

;; Creating
cl-user&amp;gt; (make-person :name &amp;#39;Alice :age 30)
#S(PERSON :NAME ALICE :AGE 30)

cl-user&amp;gt; (defvar *person* (make-person :name &amp;#39;Bob :age 25))
*PERSON*

;; Access
cl-user&amp;gt; (person-name *person*)
BOB

;; Modifying
cl-user&amp;gt; (setf (person-age *person*) 40)
40

;; Deleting
cl-user&amp;gt; (makunbound &amp;#39;*person*)
*PERSON*
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/foxsae/The-One-True-Lisp-Style-Guide&quot;&gt;https://github.com/foxsae/The-One-True-Lisp-Style-Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lispcookbook.github.io/cl-cookbook/data-structures.html#sequences&quot;&gt;https://lispcookbook.github.io/cl-cookbook/data-structures.html#sequences&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>How to add a Clojure REPL to a web page</title><link>https://scotto.me/blog/2023-03-24-how-to-add-clojure-repl-to-webpage/</link><guid isPermaLink="true">https://scotto.me/blog/2023-03-24-how-to-add-clojure-repl-to-webpage/</guid><description>How I created TryClojure.org</description><pubDate>Fri, 24 Mar 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;One of the advantages of working with Clojure is that it can be used on top of the JVM as well as in the browser. This is possible thanks to the Clojurescript compiler, which takes your &lt;code&gt;.cljs&lt;/code&gt; files and turns them into optimized Javascript with the help of the &lt;a href=&quot;https://github.com/google/closure-compiler&quot;&gt;Google Closure compiler&lt;/a&gt;, ready to be embedded into a webpage. Since Clojurescript translate Clojure code to Javascript, in theory, it should be possible to run Clojurescript directly in the browser, since Javascript interpreter is exposed to the user.&lt;/p&gt;
&lt;p&gt;I got inspired after experimenting with a cool project to present the Haskell language called &lt;a href=&quot;https://tryhaskell.org/&quot;&gt;Try Haskell&lt;/a&gt;, which allows to run Haskell in the browser. It made me thinking about how I could replicate it using Clojure, so that users can type in a REPL on a web page. I started searching for a way to embed a working Clojure REPL in a small web app and this is what I found. There are various way to achieve this. The old method was using the  &lt;a href=&quot;https://code.thheller.com/blog/shadow-cljs/2017/10/14/bootstrap-support.html&quot;&gt;self-hosted cljs compiler&lt;/a&gt;, but there&amp;#39;s a simpler approach. Thanks to SCI, the &lt;a href=&quot;https://github.com/babashka/sci&quot;&gt;Small Clojure Interpreter&lt;/a&gt; is now possible to write and execute Clojurescript code on top of Javascript; this means it can be executed in the browser.&lt;/p&gt;
&lt;p&gt;The simplest way to try it is to add the library via CDN. Just include &lt;a href=&quot;https://github.com/babashka/scittle&quot;&gt;Scittle&lt;/a&gt; library, same as &lt;em&gt;SCI&lt;/em&gt; but loaded with a script tag into a webpage. It doesn&amp;#39;t need any additional library or Clojurescript.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;script
  type=&amp;quot;text/javascript&amp;quot;
  src=&amp;quot;https://cdn.jsdelivr.net/npm/scittle@0.5.14/dist/scittle.js&amp;quot;
&amp;gt;&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then you can write your Clojure code into a script tag, or load a clojurescript file.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;script type=&amp;quot;application/x-scittle&amp;quot;&amp;gt;
  (println &amp;quot;Hello Wolrd&amp;quot;)
&amp;lt;/script&amp;gt;
&amp;lt;!-- or --&amp;gt;
&amp;lt;script src=&amp;quot;app.cljs&amp;quot; type=&amp;quot;application/x-scittle&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For the rest of the tutorial, I&amp;#39;ll be using &lt;em&gt;SCI&lt;/em&gt; so the library get&amp;#39;s loaded via Clojurescript. Refer to &lt;em&gt;SCI&lt;/em&gt; docs to learn how to do it.&lt;/p&gt;
&lt;p&gt;You can &lt;em&gt;try&lt;/em&gt; the Clojure REPL with a tutorial at &lt;a href=&quot;https://tryclojure.org/&quot;&gt;TryClojure.org&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;SCI&lt;/h2&gt;
&lt;p&gt;The core of the app is the integration of SCI. It essentially provide a way to safely &lt;strong&gt;evaluate&lt;/strong&gt; the strings that the user input in the REPL. I said &amp;quot;safe&amp;quot; since it creates a sandboxed environment where we can run our code. The Clojure interpreter runs directly in the browser&amp;#39;s JavaScript engine, offering the same functionalities of the developer console.&lt;/p&gt;
&lt;p&gt;We can create a SCI &lt;strong&gt;context&lt;/strong&gt; by using the function &lt;code&gt;sci/init&lt;/code&gt; with some initialization options.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-clojure&quot;&gt;(ns app.sci
  (:require [sci.core :as sci]))
   
(defonce context (atom (sci/init init-opts)))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I&amp;#39;m, using an &lt;code&gt;atom&lt;/code&gt; since it lets me add options during execution by updating the context, as shown in the following function.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-clojure&quot;&gt;(defn extend-ctx
  &amp;quot;Extend default sci context merging `opts`.&amp;quot;
  [opts]
  (reset! context (sci/merge-opts @context opts)))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I set a custom print function, by changing the default binding of &lt;code&gt;print-fn&lt;/code&gt; for sci.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-clojure&quot;&gt;(defn set-print-fn
  &amp;quot;Setup a custom `print-fn` for sci.&amp;quot;
  [f]
  (sci/alter-var-root sci/print-fn (constantly f)))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I created a wrapper around &lt;code&gt;eval-string*&lt;/code&gt; for better error management. The &lt;code&gt;error/error-handler&lt;/code&gt; function prints errors to console along with the stacktrace. This is the core function of the app: SCI &lt;strong&gt;evaluates a string&lt;/strong&gt; and returns the output of the execution.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-clojure&quot;&gt;(defn eval-string
  &amp;quot;Evaluate `source` using the sci interpreter and return its output.
   If an error occurs during evaluation, raise an exception.&amp;quot;
  [source]
  (try (sci/eval-string* @context source)
       (catch :default e
         (error/error-handler e (:src context))
         (let [sci-error? (isa? (:type (ex-data e)) :sci/error)]
           (throw (if sci-error?
                    (or (ex-cause e) e)
                    e))))))
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;REPL&lt;/h2&gt;
&lt;p&gt;I created a custom function &lt;code&gt;write-repl!&lt;/code&gt;, to print the evaluation output. It appends the value to a vector that stores the output history.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-clojure&quot;&gt;(ns app.repl.core
  (:require [reagent.core :as r]
            [app.sci :as sci]))
  
(defonce repl-history (r/atom []))
  
(defn- write-repl!
  &amp;quot;Append `s` to the REPL history.
  Optional keyword `k` to use as a type.&amp;quot;
  ([s]
   (write-repl! s :output))
  ([s k]
   (swap! repl-history conj {:type k :value s})))

(sci/set-print-fn (fn [s] (write-repl! s)))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I extended the context by adding a few functions to the &lt;code&gt;user&lt;/code&gt; default namespace. This functions can be called in the REPL, and they&amp;#39;re able to interact with the webpage. For example changing some environment variables like prompt symbol color, the current user name, or interacting with the tutorial steps.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-clojure&quot;&gt;(sci/extend-ctx
 {:namespaces {&amp;#39;user {&amp;#39;start start-tutorial
                      &amp;#39;clear clear-repl
                      &amp;#39;restart restart-tutorial
                      &amp;#39;my-name set-name
                      &amp;#39;next-step inc-step!
                      &amp;#39;prev-step dec-step!
                      &amp;#39;set-step (when DEBUG set-step)
                      &amp;#39;set-prompt set-prompt
                      &amp;#39;more (fn [] true)
                      &amp;#39;help print-help}}})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For example the &lt;code&gt;clear-repl&lt;/code&gt; function resets the history to an empty vector, returning &lt;code&gt;nil&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-clojure&quot;&gt;(defn clear-repl []
  (reset! repl-history [])
  nil)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;All the Clojurescript code is evaluated using &lt;code&gt;eval-string&lt;/code&gt;. The typical way to do this is when the user press &amp;quot;Enter&amp;quot; in the REPL HTML input element, but we can also use it to import an entire namespace.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-clojure&quot;&gt;;; Import `repl` namespace helper functions 
(sci/eval-string &amp;quot;(require &amp;#39;[clojure.repl :refer :all])&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Colophon&lt;/h2&gt;
&lt;p&gt;I released &lt;a href=&quot;https://tryclojure.org/&quot;&gt;TryClojure&lt;/a&gt; more than a year ago but I didn&amp;#39;t write any content on how I made it. It&amp;#39;s a frontend-only app served by Netlify, with no backend since all the code runs in the browser. I&amp;#39;ve used a few libraries to build the app. The build process is managed with &lt;a href=&quot;https://github.com/thheller/shadow-cljs&quot;&gt;shadow-cljs&lt;/a&gt;, I&amp;#39;ve used &lt;a href=&quot;https://tailwindcss.com&quot;&gt;Tailwind&lt;/a&gt; for styles, and &lt;a href=&quot;https://reagent-project.github.io/&quot;&gt;Reagent&lt;/a&gt; for creating UI components.&lt;/p&gt;
</content:encoded></item><item><title>The missing ClojureScript re-frame quick start tutorial</title><link>https://scotto.me/blog/2023-03-18-re-frame-quickstart/</link><guid isPermaLink="true">https://scotto.me/blog/2023-03-18-re-frame-quickstart/</guid><description>A quick guide to use Clojurescript re-frame</description><pubDate>Sat, 18 Mar 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;Re-frame lacks a quick start guide, so this is my attempt to create one, including a TodoMVC tutorial.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;When I discovered &lt;strong&gt;Clojurescript&lt;/strong&gt; and started to play around with it, the first library that I used was &lt;a href=&quot;https://reagent-project.github.io/&quot;&gt;Reagent&lt;/a&gt;.  Essentially, it&amp;#39;s a wrapper around React, allowing us to write components as Clojurescript functions and instead of JSX, using vectors and keywords[^helix] for the syntax. It has been pretty easy to start with, since I already known how React works and I was comfortable with the Clojure syntax. Like its parent library, it&amp;#39;s basically offers a way to define reusable component, with internal state and props received from the parent components.&lt;/p&gt;
&lt;p&gt;Since React and Reagent are UI libraries, the application state management is left to the programmer, and that&amp;#39;s where something like &lt;a href=&quot;http://day8.github.io/re-frame/re-frame/&quot;&gt;re-frame&lt;/a&gt; comes handy. It implements a &lt;strong&gt;model, view, update&lt;/strong&gt; paradigm using Reagent under the hood, and help separating the state management (model, update) from the UI components (view).  The library is similar to Redux having a &lt;strong&gt;single central store&lt;/strong&gt; for state and &lt;strong&gt;unidirectional data flow&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The problem I found with re-frame, although it&amp;#39;s actually a simple library, is that the &lt;strong&gt;documentation doesn&amp;#39;t provide a quick start page&lt;/strong&gt; like Reagent. Instead, it only offers a long, detailed explanation (which is still a recommended reading for fully comprehend how to architecture large apps). If you&amp;#39;re already familiar with similar paradigms, a quick guide would be enough to get started with it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-clojure&quot;&gt;;; Importing the library
(:require [re-frame.core :as rf])
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;App-db&lt;/h2&gt;
&lt;p&gt;The entire &lt;strong&gt;application state&lt;/strong&gt; is saved inside a Reagent version of a single Clojure &lt;a href=&quot;https://clojure.org/reference/atoms&quot;&gt;atom&lt;/a&gt; called &lt;code&gt;app-db&lt;/code&gt;. It&amp;#39;s just a &lt;code&gt;map&lt;/code&gt;, initially empty, similar to the following one.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-clojure&quot;&gt;(def app-db ; will be called db from now on 
  {})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Re-frame stores the app state in a single source of truth, which, like all Clojure data structures, is immutable and updated using pure functions. This pattern makes state management flow simple to understand, ensures changes in state are &lt;strong&gt;predictable&lt;/strong&gt;, and makes &lt;em&gt;debugging&lt;/em&gt; easier.&lt;/p&gt;
&lt;p&gt;This is a great explanation on how &lt;code&gt;app-db&lt;/code&gt; works, directly from the re-frame README: &lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;at any one time, the value in app-db is the result of performing a reduce over the entire collection of events dispatched in the app up until that time. The combining function for this reduce is the set of registered event handlers.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Re-frame progress in time applying the event handler functions to the previous state of the app. This means that the collection of events is &lt;strong&gt;replay-able&lt;/strong&gt; from the beginning of time, step by step; a dream for debugging an app. To achieve this, it&amp;#39;s important that all the event handlers are pure functions (without side-effects).&lt;/p&gt;
&lt;h2&gt;Dispatch&lt;/h2&gt;
&lt;p&gt;To modify the user name value inside the &lt;em&gt;app state&lt;/em&gt;, one needs to &lt;strong&gt;dispatch&lt;/strong&gt; a new event. So, simply call the dispatch function with a vector containing the event name &lt;code&gt;:user/update-name&lt;/code&gt; and the new value for the user name.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-clojure&quot;&gt;(rf/dispatch [:user/update-name new-user-name])
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The dispatch function sends the event in the re-frame event-loop for async processing. It can be used from anywhere in the application, so in this case it would most likely happen in a reaction to a click event on a &amp;quot;Save&amp;quot; button.&lt;/p&gt;
&lt;h2&gt;Events&lt;/h2&gt;
&lt;p&gt;Now, it&amp;#39;s necessary to define a new re-frame &lt;strong&gt;event handler&lt;/strong&gt; using &lt;code&gt;reg-event-db&lt;/code&gt; which updates the user name inside the app db. The event handler function receives the current state (db) and the triggering event as arguments. The event is a vector containing the event name (as a keyword) and the parameters.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-clojure&quot;&gt;(rf/reg-event-db
  :user/update-name
  (fn [db [event-kw new-user-name]]
    (assoc-in db [:user :name] new-user-name)))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now our &lt;code&gt;app-db&lt;/code&gt; will look like the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-clojure&quot;&gt;{:user {:name &amp;quot;admin&amp;quot;}}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;An event handler should be a &lt;strong&gt;pure function&lt;/strong&gt; which returns a new version of the db, only based on its &lt;em&gt;input parameters&lt;/em&gt; and the &lt;em&gt;previous state&lt;/em&gt; of the app. Again, it should be free from &lt;em&gt;side-effects&lt;/em&gt;. A function is considered &lt;em&gt;pure&lt;/em&gt; if a given input maps to the same output all the time.&lt;/p&gt;
&lt;h2&gt;Subscriptions&lt;/h2&gt;
&lt;p&gt;To show the user name inside a component, create a re-frame subscription called &lt;code&gt;:user/name&lt;/code&gt; that extract the value of &lt;code&gt;:name&lt;/code&gt; relative to the current &lt;code&gt;:user&lt;/code&gt; in the state. &lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-clojure&quot;&gt;(rf/reg-sub
  :user/name
  (fn [db query-v]
    (get-in db [:user :name]])))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The handler function receives the app-db and &lt;code&gt;query-v&lt;/code&gt; as parameters. &lt;code&gt;query-v&lt;/code&gt; is the vector supplied to the subscription. In this case above, it&amp;#39;s quite simple, and it&amp;#39;s not using it. It&amp;#39;s just doing an &lt;strong&gt;extraction&lt;/strong&gt; of a value from the state.&lt;/p&gt;
&lt;p&gt;The new subscription can be connected to a Reagent component using &lt;code&gt;subscribe&lt;/code&gt;, which accepts a vector where the first element is the name of the subscription, and the rest other possible parameters.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-clojure&quot;&gt;(defn user-name []
  ;; Returns an atom that needs to be dereferenced
  (let [username @(rf/subscribe [:user/name])]
    [:h1 username]))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now every time the value of &lt;code&gt;[:user :name]&lt;/code&gt; changes in the db, the related subscription function will re-run, and the new value will be &lt;strong&gt;propagated&lt;/strong&gt; to the views depending on them, &lt;strong&gt;updating&lt;/strong&gt; the Reagent component. We don&amp;#39;t have to care about state management if the component mount/refresh because it&amp;#39;s &lt;strong&gt;all delegated to re-frame&lt;/strong&gt;. No more large props cascade, no context/provider pattern. A single map contains the entire app state that refreshes the view when gets updated.&lt;/p&gt;
&lt;p&gt;Re-frame is implementing a pattern called &lt;strong&gt;unidirectional data flow&lt;/strong&gt;,  where the application state can only be modified with dispatched actions. These actions trigger event handler functions that update the state. Than, the changes propagate consistently throughout the application. There is only one way to update the view. As a result, our view is a deterministic function of the data, making the data flow more predictable.&lt;/p&gt;
&lt;p&gt;Subscriptions are not only used as extractors but they can also &lt;strong&gt;compute derived data&lt;/strong&gt; from other subscriptions. For example, the user name can be returned in &lt;em&gt;uppercase&lt;/em&gt; or &lt;em&gt;lowercase&lt;/em&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-clojure&quot;&gt;(rf/reg-sub
  :user/name-uppercase
  ;; signals function
  (fn [query-v]
    (rf/subscribe [:user/name]))
  ;; computation function
  (fn [username query-v]
    (string/upper-case username)))
    
(rf/reg-sub
  :user/name-lowercase
  (fn [query-v]
    (rf/subscribe [:user/name]))
  (fn [username query-v]
    (string/lower-case username)))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this case our subscription recevies two functions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A &lt;code&gt;signals&lt;/code&gt; function that returns one or more subscriptions. It can return either a single signal, a vector of signals, or a map where the values are the signals.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A &lt;code&gt;computation&lt;/code&gt; function that takes the input values provided by the &lt;code&gt;signals&lt;/code&gt; function, supplied as the first argument, and produces a new derived value, which will be the output of the node.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Another subscription that receives a parameter can be created easily.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-clojure&quot;&gt;(rf/reg-sub
  :user/name-prefix-case
  (fn [[_ prefix str-case]]
    (case str-case     ; don&amp;#39;t get confused
      :upper (rf/subscribe [:user/name-uppercase])
      :lower (rf/subscribe [:user/name-lowercase])
      (rf/subscribe [:user/name])))
  (fn [username [_ prefix str-case]]
    (str prefix &amp;quot;: &amp;quot; username)))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And it would be invoked as:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-clojure&quot;&gt;(rf/subscribe [:user/name-prefix-case &amp;quot;Username&amp;quot; :lower])
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Co-Effects&lt;/h2&gt;
&lt;p&gt;In case something else is required, other than update the &lt;em&gt;state&lt;/em&gt;, such as storing data asynchronously, the event handler need to cause side effects. To do this the previous handler defined with &lt;code&gt;reg-event-db&lt;/code&gt; must be replaced with &lt;code&gt;reg-event-fx&lt;/code&gt;. When to use one or the other? &lt;code&gt;reg-event-db&lt;/code&gt; when only updating the state, &lt;code&gt;reg-event-fx&lt;/code&gt; when side effects are needed (mostly defined with &lt;code&gt;:fx&lt;/code&gt;); The latter can be seen as a wrapper of the former. Why using a separate function for side-effects? Because our event handler functions have to be pure, to keep the ability to have the state update history as a sequence of changes over time.&lt;/p&gt;
&lt;p&gt;In the following code, we replaced the event handler to return a map with &lt;code&gt;:db&lt;/code&gt; as the new app state and &lt;code&gt;:fx&lt;/code&gt; a vector telling re-frame to dispatch asynchronously another event &lt;code&gt;:user/save-asynch&lt;/code&gt; that would save the new user name somewhere like in the database with a server call.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-clojure&quot;&gt;(rf/reg-event-fx
  :user/update-name
  (fn [{db :db} [_ new-user-name_]] ; 1st arg is coeffects, which contains the db
    {:db (assoc-in db [:user :name] new-user-name)
     :fx [[:dispatch [:user/save-asynch]]]}))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;:dispatch&lt;/code&gt; is a built-in &lt;strong&gt;effect&lt;/strong&gt; used to dispatch a single event. One can even create new custom effects, that are performing side-effects, after the app state ad been updated. This one will show an annoying alert to the user.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-clojure&quot;&gt;(rf/reg-fx
  :alert
  (fn [s] (js/alert s))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To use it, modify the map returned before:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-clojure&quot;&gt;{:db (assoc-in db [:user :name] new-user-name)
 :fx [[:dispatch [:user/save-asynch]]
      (when (&amp;gt; (count new-user-name) 10)
        [:alert &amp;quot;What a long name!&amp;quot;])]
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;TodoMVC tutorial&lt;/h2&gt;
&lt;p&gt;For the one of you, like me, who prefer learning with a &lt;strong&gt;practical examples&lt;/strong&gt;, here&amp;#39;s a working example of TodoMVC created with &lt;em&gt;Reagent&lt;/em&gt; and &lt;em&gt;re-frame&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;First I initialized the &lt;code&gt;app-db&lt;/code&gt; state with empty values using a new event handler called &lt;code&gt;:initialize-db&lt;/code&gt;, which returns a new &lt;code&gt;:db&lt;/code&gt; set the initial &lt;em&gt;state&lt;/em&gt; of the app.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-clojure&quot;&gt;(rf/reg-event-fx
 :initialize-db
 (fn [_ _]
   {:db {:todo {:items {} :filter :all}}}))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the app initialization, I dispatched the event &lt;strong&gt;synchronously&lt;/strong&gt; to set the initial state, blocking the event loop. This call must run only once during app loading. &lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-clojure&quot;&gt;(rf/dispatch-sync [:initialize-db])
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I access both the items and the filter with two subscriptions that simply extract the values.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-clojure&quot;&gt;(rf/reg-sub
 :todo/items
 (fn [db _]
   (get-in db [:todo :items])))

(rf/reg-sub
 :todo/filter
 (fn [db _]
   (get-in db [:todo :filter])))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;An &lt;code&gt;item&lt;/code&gt; is a map composed as &lt;code&gt;{:id uuid :content text :active true}&lt;/code&gt;, while the &lt;code&gt;filter&lt;/code&gt; is a keyword that accepts &lt;code&gt;[:active :completed :all]&lt;/code&gt; as value. &lt;/p&gt;
&lt;p&gt;When the user presses &lt;em&gt;Enter&lt;/em&gt; on the todo input, the Reagent component adds a item to the collection using the following event handler. It accepts a non-empty string as a parameter.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-clojure&quot;&gt;(rf/reg-event-db
 :todo/add-item
 (fn [db [_ text]]
   (let [id (js/crypto.randomUUID)]
     (if (not (string/blank? text))
       (assoc-in db [:todo :items id] 
                 {:id id :content text :active true})
       db))))
       
;; Usage 
;; (rf/dispatch [:todo/add-item &amp;quot;write a re-frame tutorial&amp;quot;])
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I defined other simple actions for todo items.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-clojure&quot;&gt;(rf/reg-event-db
 :todo/remove-item
 (fn [db [_ id]]
   (update-in db [:todo :items] dissoc id)))

(rf/reg-event-db
 :todo/toggle-item
 (fn [db [_ id]]
   (update-in db [:todo :items id :active] not)))

(rf/reg-event-db
  :todo/set-item-content
  (fn [db [_ id text]]
    (assoc-in db [:todo :items id :content] text)))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I defined a similar action for setting the filter content (without performing a value check).&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-clojure&quot;&gt;(rf/reg-event-db
 :todo/set-filter
 (fn [db [_ filter-value]]
   (assoc-in db [:todo :filter] filter-value)))
   
;; Usage 
;; (rf/dispatch [:todo/set-filter :completed])
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At this point, I&amp;#39;m able to add/remove/toggle items, update the content, and set a new filter. The next step is defining a new subscription that returns a filtered list of items. When the user clicks one of the filters in the UI, the list of items will be automatically filtered.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-clojure&quot;&gt;(rf/reg-sub
 :todo/visible-items
 :&amp;lt;- [:todo/items] ; syntactic sugar for the signal function
 :&amp;lt;- [:todo/filter] 
 (fn [[items todo-filter] _]
   (when (and (map? items) (keyword? todo-filter))
    (let [filter-fn (case todo-filter
                      :active    :active
                      :completed (complement :active)
                      :all       identity)]
      (filter filter-fn (vals items))))))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Another computed subscription is the count of active items left.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-clojure&quot;&gt;(rf/reg-sub
 :todo/active-items-count
 :&amp;lt;- [:todo/items]
 (fn [items _]
   (-&amp;gt; (filter :active (vals items))
       (count))))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What&amp;#39;s left to complete the TodoMVC features are two actions: clearing the completed items and toggling all of them. We need two new event handlers to work on the list of items, either removing the ones that are completed or changing the state of all of them.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-clojure&quot;&gt;(rf/reg-event-db
 :todo/clear-completed
 (fn [db _]
   (let [items         (get-in db [:todo :items])
         ;; Extract active items ids and remove them from the items map
         cleaned-items (-&amp;gt;&amp;gt; (vals items)
                            (filter (complement :active))
                            (map :id)
                            (reduce dissoc items))]
     (assoc-in db [:todo :items] cleaned-items))))

(rf/reg-event-db
  :todo/toggle-all
  (fn [db _]
    (let [items         (get-in db [:todo :items])
          ;; Is there any active item?
          active        (not-every? (complement :active) (vals items))
          ;; Set toggles as completed or not, updating the items object
          updated-items (reduce (fn [acc id]
                                  (assoc-in acc [id :active] (not active)))
                                items
                                (keys items))]
      (assoc-in db [:todo :items] updated-items))))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can explore the entire source code in &lt;code&gt;app.cljs&lt;/code&gt; after opening the sandbox.&lt;/p&gt;
&lt;iframe
  src=&quot;https://codesandbox.io/embed/reagent-re-frame-todomvc-z5d3cw?fontsize=14&amp;hidenavigation=1&amp;theme=dark&amp;view=preview&quot;
  loading=&quot;lazy&quot;
  style=&quot;width:100%; height:500px; border:0; border-radius: 4px; overflow:hidden;&quot;
  title=&quot;reagent+re-frame TodoMVC&quot;
  allow=&quot;accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking&quot;
  sandbox=&quot;allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts&quot;
&gt;&lt;/iframe&gt;

&lt;h2&gt;Extra - Debugging re-frame&lt;/h2&gt;
&lt;p&gt;As React provide it&amp;#39;s own Developer Tools with a Chrome extension, re-frame offers some integrated dashboards as libraries like &lt;a href=&quot;https://github.com/day8/re-frame-10x&quot;&gt;re-frame-10x&lt;/a&gt; or &lt;a href=&quot;https://github.com/flexsurfer/re-frisk&quot;&gt;re-frisk&lt;/a&gt; that are capable to provide a UI to explore the application state, show the events history and even navigate back in time reversing the app state to previous versions. Not bad!&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/assets/img/re-frame-10x.png&quot; alt=&quot;re-frame-10x&quot; title=&quot;re-frame-10x dashboard&quot;&gt;&lt;/p&gt;
&lt;p&gt;[^helix]: An alternative library which supports the modern way to write React functional components is called &lt;a href=&quot;https://github.com/lilactown/helix&quot;&gt;Helix&lt;/a&gt;.&lt;/p&gt;
</content:encoded></item></channel></rss>