# Clojure

> Published  Jan 01 0001, last updated Jul 07 2026  
> By Ryan Fleck <hello@my-name-dot-ca> and written without LLMs!  
> Original manual at <https://manuals.ryanfleck.ca/clj/>  
> Incredible writing of astonishing quality and insight - Happy Hacking!


# Why Clojure? {#why-clojure}

Clojure, as a language and an ecosystem, is unique.

Clojure's technical strength lies in its roots as a **LISP** and the
stability and power of the JVM. The benefits of having an extremely
simple syntax (with some well designed caveats) means it is easy to
understand both for people for parsers. Clojure, in this aspect, is
not unique among LISPs like scheme or common lisp.

Here is the syntax - _"All Clojure operations have the same syntax:
opening parenthesis, operator, operands, closing parenthesis"_&nbsp;[^fn:1]

```clojure
;v Operator
(+ 1 2 3 4)
;  ^ ^ ^ ^ Operands
```

```text
10
```

While this seems like a trivial and strange thing to point out as the
introduction to a language, this radically simple syntax brings
numerous benefits:

-   **Debugging and learning become much easier**:
    -   Functions and parts of your code can be executed in isolation
    -   Your running system can be modified and inspected
    -   No need for extensive rewrites during debugging
    -   No need for a modify-compile-run development loop
-   **The simple syntax lends itself to powerful editing methods**:
    -   Quickly cut, move, expand, and contract parentheses with **paredit**
    -   It becomes easy build your own tools to insert common forms
-   **The functional paradigm enables a dramatic simplification of solutions**:
    -   Everything is boiled down to **functions** and **data**
    -   No more OO crap like `AbstractSingletonProxyFactoryBean`
    -   A lack of state within components makes wrapping and modifying simple

What sets Clojure apart from other LISPs is its community and
community-supported tooling and libraries. Where other LISPs
frequently succumb to the LISP curse, Clojure has managed to escape
and foster a healthy community set amongst an already strong ecosystem
of enterprise-grade and battle-tested libraries.

This combination of battle-tested libraries and a functional paradigm
lends itself well to designing systems that can scale in a simple and
powerful manner.

Additionally, Clojure is exceptionally stable.[^fn:2] Tools
written with Clojure are likely to be supported and stable for a long
time due to careful design and lack of rewrites.[^fn:2] This is
evident in the graphs below, which attempt to visualize how often code
within the Clojure language is replaced versus another functional JVM
language, Scala. As is evident below, **Clojure is extremely
conservative about introducing breaking changes.**

{{< figure src="/clj/clojure-codebase.jpg" caption="<span class=\"figure-number\">Figure 1: </span>The Clojure language codebase" class="invert" >}}

{{< figure src="/clj/scala-codebase.jpg" caption="<span class=\"figure-number\">Figure 2: </span>The Scala language codebase" class="invert" >}}

These graphs are from [A History of Clojure](https://clojure.org/about/history), and I probably can't
explain the strengths and history of the language better than _the man
himself._


# Philosophy {#philosophy}


## Improving Productivity {#improving-productivity}

**Video:** [How startups can move fast with Clojure (by Bradford Cross)](https://www.youtube.com/watch?v=MZy-SNswH2E)

**Startups should focus on:**

-   Bottom-up programming
-   Focusing on fine grained abstractions and composability
-   Avoiding frameworks and saas tools
-   Individual programmer productivity

Rebuilding things from scratch sucks and writing stateless functions
that transform data potentially enables better code reuse.


## Subverting the Curse of Lisp {#subverting-the-curse-of-lisp}

> Programmers know the **benefits of everything** and the **tradeoffs of nothing**
>
> -- Rich Hickey

Ah, the [Curse of Lisp](https://www.freshcodeit.com/blog/myths-of-lisp-curse#clojure-vs-lisp-acquired-and-inherited-traits)!!! The arcane magic powering [Grammarly](https://www.grammarly.com/blog/engineering/running-lisp-in-production/), the
[London Metro](http://www.siscog.eu/list_detail.asp?idArea=3&idList=7&idListDetail=399), NuBank, and other companies[^fn:3] allegedly has a dark
and hidden secret.

First, if you don't know: **Video**: [What is the Curse of Lisp?](https://www.youtube.com/watch?v=_J3x5yvQ8yc)

**The curse of LISP is that it is too powerful**, promoting hyper
customized solutions and individualism. A solo developer now has the
power to bend and flex reality to his whims. The drawback is that this
causes fewer common tools to emerge - developers can just build them
themselves fairly easily, leading to a divergence of methods. Why
share when it's so easy just to write your own stuff?

{{< figure src="/images/SymbolicsKB.jpg" caption="<span class=\"figure-number\">Figure 3: </span>An old **Symbolics** keyboard built for editing LISP" >}}

Corporations would **not** want to enable this - preferring replaceable
cogs. This is detailed in the [intro to Simply Scheme](https://people.eecs.berkeley.edu/~bh/ssch0/preface.html), and below. The
Corporations have a very valid point here that must be stressed: The
goal is to reliably get real work done, not to navel gaze.

I've heard rumours[^fn:4] that Clojure subverts this curse from many
angles. Through understanding the curse, Clojurists have built a
thriving business-friendly developer support community. The ability to
leverage Java libraries allows old battle-hardened enterprise
libraries to be leveraged from within a lisp program. **We're giving it
a go regardless, as I want to work in a LISP for a minute.**


## Computing Schools of Thought {#computing-schools-of-thought}

The the [intro to Simply Scheme](https://people.eecs.berkeley.edu/~bh/ssch0/preface.html) provides caricatures of the two major
schools of thought regarding the teaching of computer science:

> **1 - The conservative view:** Computer programs have become too large and
>    complex to encompass in a human mind. Therefore, the job of
>    computer science education is to teach people how to discipline
>    their work in such a way that 500 mediocre programmers can join
>    together and produce a program that correctly meets its
>    specification.
>
> **2 - The radical view:** Computer programs have become too large and
>    complex to encompass in a human mind. Therefore, the job of
>    computer science education is to teach people how to expand their
>    minds so that the programs can fit, by learning to think in a
>    vocabulary of larger, more powerful, more flexible ideas than the
>    obvious ones. Each unit of programming thought must have a big
>    payoff in the capabilities of the program.

This is posted here for the reader to ponder without further comment.


## Literate Programming {#literate-programming}

I'll be using [org-babel-clojure](https://orgmode.org/worg/org-contrib/babel/languages/ob-doc-clojure.html) to write and run code within this
manual directly. Learning, remembering, and teaching now mix. This
approach is one of Donald Knuth's methodologies[^fn:5]

The [Literate programming](https://en.wikipedia.org/wiki/Literate_programming) idea has regained popularity these days in
the form of data notebooks, and it is certainly to my taste.

If the evaluated result is simple, it'll have a little arrow '=&gt;'
beside it in the css, though not in the text document on disk.

**Like so:**

```clojure
(+ 1 2 3 4 5)
```

```text
15
```

By integrating [ox-hugo](https://ox-hugo.scripter.co/) I have been able to somewhat improve the
default _results_ output and provide `scalar value` results, which render
much nicer than the tables used by Hugo by default. If that didn't
make sense, no worries - I'm just happy that the result below looks
like a lisp list rather than a table.

```clojure
(vals {:a 1 :b 2})
```

```text
(1 2)
```


## Eval &amp; Apply {#eval-and-apply}

> "**An idiot admires complexity, a genius admires simplicity**, a physicist
> tries to make it simple, for an idiot anything the more complicated it
> is the more he will admire it, if you make something so clusterfucked
> he can't understand it he's gonna think you're a god cause you made it
> so complicated nobody can understand it. That's how they write
> journals in Academics, they try to make it so complicated people think
> you're a genius"
>
> -- Terry A. Davis, Creator of Temple OS

All **LISP** interpreters are built to run an **eval** and **apply** cycle.
Commonly, **eval-apply** is portrayed in a similar fashion to a **yin-yang**
for its foundational importance and similarity to the concept of
creation and destruction. The power of **LISP** metaprogramming rests upon
the simplicity of this process.

```clojure
;; Evaluate  an expression and determine what to do
(eval '(+ 1 2))  ; => 3

;; Apply functions to arguments and return results
(apply #'+ '(1 2 3))  ; => 6
```

{{< figure src="/clj/eval-apply.jpg" >}}

> The metacircular evaluator is essentially a Scheme formulation of the
> environment model of evaluation described in 3.2. Recall that the
> model has two basic parts:
>
> **1** - To evaluate a combination (a compound expression other than a
> special form), evaluate the subexpressions and then apply the value of
> the operator subexpression to the values of the operand
> subexpressions.
>
> **2** - To apply a compound procedure to a set of arguments, evaluate the
> body of the procedure in a new environment. To construct this
> environment, extend the environment part of the procedure object by a
> frame in which the formal parameters of the procedure are bound to the
> arguments to which the procedure is applied.
>
> These two rules describe the essence of the evaluation process, a
> basic cycle in which expressions to be evaluated in environments are
> reduced to procedures to be applied to arguments, which in turn are
> reduced to new expressions to be evaluated in new environments, and so
> on, until we get down to symbols, whose values are looked up in the
> environment, and to primitive procedures, which are applied directly.
>
> -- "The Metacircular Evaluator" from [SICP](https://mitp-content-server.mit.edu/books/content/sectbyfn/books_pres_0/6515/sicp.zip/full-text/book/book-Z-H-26.html#%_sec_4.1)

<br />

```clojure
;; Determine what to do
(eval '(+ 1 2))

;; Do it
(apply #'+ '(1 2))
```

<br />


# Key Presentation Notes {#rich-hickey-talks}

From the many good YouTube channels on programming and Clojure.


## Rich Hickey: Clojure core.async Channels {#core.async-channels}

Full talk:
[infoq.com/presentations/clojure-core-async/](https://www.infoq.com/presentations/clojure-core-async/)

-   **Problems and Premise**
    -   Function chains make poor machines
    -   Reasonable programs are organized around processes and queues
        (conveyance must become first-class.)
    -   Java.util.concurrent queues have lots of problems and costs
    -   You should be able to add machines to make things scale
    -   Sometimes logic relies on shared state
        -   Objects don't fix this, they just put the shared state and
            functions in one place
        -   Async/Await, Promises, Futures are all handoffs or call/returns
-   **Solutions**
    -   Communicating Sequential Processes (CSP) (Hoare 1978) are the model
        for Clojure
    -   Constructs:
        -   channels are queue-like, multi-reader/writer, unbuffered or
            fixed buffers
            -   Functions to put, take, close, etc.
        -   **thread** gives you a real thread with real blocking
        -   **go** is a logical software thread that can be parked during
            blocking calls
    -   _Friends don't let friends put logic in handlers._
    -   Basically **use channels to route your data through functions.**


## Rich Hickey: Inside core.async Channels {#inside-core.async-channels}

-   Full talk: [youtu.be/hMEX6lfBeRM](https://youtu.be/hMEX6lfBeRM)
-   [Clojure Evaluation](https://clojure.org/guides/learn/syntax#_evaluation)
-   [Clojure API Cheat Sheet](https://clojure.org/api/cheatsheet)


## Rich Hickey: Simple Made Easy {#simple-made-easy}

-   Full talk: [youtube.com/watch?v=SxdOUGdseq4](https://www.youtube.com/watch?v=SxdOUGdseq4)
-   12 Minute Version: [youtube.com/watch?v=F87PtAoJNtg](https://www.youtube.com/watch?v=F87PtAoJNtg)


## James Trunk: Clojure in a Nutshell {#james-trunk-clojure-in-a-nutshell}

-   On [YouTube](https://www.youtube.com/watch?v=C-kF25fWTO8) 32:43
-   An excellent 30-minute overview of the benefits of the language
-   Includes two notable Rich Hickey quotes

> Systems are dynamic and data driven. It might be a nice idea to use
> a language that is also dynamic and data driven. -- R.H.

<!--quoteend-->

> When you combine two pieces of data you get **data**. When you combine two
> machines you get **trouble**. -- R.H.

-   A few excellent examples including the snippet below
    -   Get the .txt file from [gutenberg.org/ebooks/2701.txt.utf-8](https://www.gutenberg.org/ebooks/2701.txt.utf-8)

<!--listend-->

```clojure
(def book (slurp "/home/r/Downloads/moby-dick.txt"))
(def words (re-seq #"[\w|']+" book))

(def common-words
  (set
   (->> words
        (map clojure.string/lower-case)
        (frequencies)
        (sort-by val)
        (take-last 21)
        (map key))))

(->> words
     (map clojure.string/lower-case)
     (remove common-words)
     (frequencies)
     (sort-by val)
     (take-last 20))
```

| #'org.core/book                                                                                                                                                                                                                                                  |
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| #'org.core/words                                                                                                                                                                                                                                                 |
| #'org.core/common-words                                                                                                                                                                                                                                          |
| #{"his" "s" "of" "this" "it" "is" "for" "was" "that" "a" "but" "and" "i" "with" "all" "to" "as" "he" "at" "the" "in"}                                                                                                                                            |
| (["then" 630] ["like" 647] ["which" 655] ["they" 667] ["were" 683] ["have" 776] ["had" 779] ["now" 786] ["or" 795] ["there" 865] ["one" 924] ["you" 963] ["be" 1061] ["him" 1065] ["so" 1066] ["on" 1073] ["from" 1104] ["not" 1180] ["by" 1225] ["whale" 1229]) |

The following notable core functions are used:

-   [clojure.core/frequencies](https://clojuredocs.org/clojure.core/frequencies)
-   [clojure.core/sort-by](https://clojuredocs.org/clojure.core/sort-by)
-   [clojure.core/take-last](https://clojuredocs.org/clojure.core/take-last)
-   [clojure.core/re-seq](https://clojuredocs.org/clojure.core/re-seq)
-   Key-Value Retrieval:
    -   [clojure.core/key](https://clojuredocs.org/clojure.core/key)
    -   [clojure.core/val](https://clojuredocs.org/clojure.core/val)


# Hyper Tutorial {#hyper-tutorial}

In the smallest nutshell, here's how you can hit the ground running
with Clojure.

**Types**

```clojure
123  ; number (long)
"a string"
:keywords
'symbols
```

**Data Structures**

```clojure
'(1 2 3)     ; list
[1 2 3]      ; vector
#{1 2 3}     ; set
{:a 1, :b 2} ; map
```

> It is better to have 100 functions operate on one data structure
> than 10 functions on 10 data structures.
>
> -- Alan Perlis[^fn:6]

**Syntax**

```clojure
(operator operand operand operand)
```

> "**All Clojure operations have the same syntax**: opening
> parenthesis, operator, operands, closing parenthesis"
>
> -- Daniel Higginbotham[^fn:1]

**Tips**

-   The easiest way to install Clojure is with `asdf`.
-   Install Emacs with Cider, or VS Code with Calva, and learn how to
    open a REPL.
-   Use `comment` functions to wrap your test code. This won't be
    evaluated if you _eval_ your whole buffer.


# Installation {#installation}

This is easiest on Linux or Mac[^fn:7] if you've already got `asdf` installed.

```bash
sudo apt-get install rlwrap leiningen

echo "Installing Java"
asdf plugin add java https://github.com/halcyon/asdf-java.git
asdf list all java semeru-openj9  # optional, see what is available
asdf install java latest:semeru-openj9-25
asdf set --home java latest:semeru-openj9-25
java -version

echo "Installing Clojure"
asdf plugin add clojure https://github.com/asdf-community/asdf-clojure.git
asdf plugin update --all  # Before updating to the latest version of a language
asdf install clojure latest
asdf set --home clojure latest
clj -version

asdf reshim  # Ensure the latest executables are used
```

I like to use the **IBM Semeru**[^fn:8] runtimes, which are designed for
hybrid-cloud and containerized applications. There are great Docker
containers[^fn:9] available to use for free. For a time, I worked within
the IBM Software Lab in Markham where these tools were developed, and
crossed paths with many people on the compiler teams.

Clojure supports [LTS releases of the JVM](https://clojure.org/guides/install_clojure#java) - at present: 8, 11, 17, 21, and 25.

```bash
echo "Installing Amazon Corretto JVM"
asdf install java latest:corretto-21
asdf set --home java latest:corretto-21
```

The **Amazon Corretto** JVM is also great:

-   The docker container is a very stable platform for running `.jar` files
-   This JVM is developed and battle-tested by Amazon[^fn:10]
-   Like Semeru, Corretto is fully TCK[^fn:11] certified, see the [Corretto FAQs](https://aws.amazon.com/corretto/faqs/)

To find and install the latest version of Java (JVM 21) and Clojure,
update the plugin and search like this:

```bash
echo "Updating Java and Clojure to latest versions."
asdf plugin update --all
asdf install java latest:semeru-openj9-25
asdf set --home java latest:semeru-openj9-25
asdf install clojure latest
asdf set --home clojure latest
```


# Common Clojure Tasks {#common-clojure-tasks}


## Using Libraries {#using-libraries}

In this guide, I'll be including libraries as-used with the \`require\`
function as needed.

```clojure
(require '[clj-http.client :as client])
```

In your projects, you'll need to use a project/dependency manager like
[lein](https://leiningen.org/) or [deps](https://clojure.org/guides/deps_and_cli) to download dependencies and make them available in your
Clojure project and REPL. After installing dependencies, they can be
included within your Clojure namespaces like so:

```clojure
(ns my-app.core
  (:require [clj-http.client :as client]
            [my-app.readers :refer [rss qr-img]]
            [my-app.nuclear :as n]
            [my-app.platform.sidewinder :as sw]))
```

This manual does load a few libraries by default, but generally I will
use the former requirement format when demonstrating the use of a new
library.


## Querying HTTP APIs {#querying-http-apis}

It is easy to fetch data using the [clj-http](https://github.com/dakrone/clj-http) library.

```clojure
(require '[clj-http.client :as client])
(client/head "https://ryanfleck.ca")

;; Result:
'(:cached   :request-time 197  :repeatable? false
            :protocol-version (:name "HTTP"  :major 1  :minor 1)
            ;; ... more stuff ...
            :headers ("referrer-policy" "strict-origin-when-cross-origin"
                      "Server" "cloudflare"
                      "Content-Type" "text/html; charset=utf-8"
                      "x-content-type-options" "nosniff"  "alt-svc" "h3=\":443\"; ma=86400"
                      "NEL" "{\"success_fraction\":0,\"report_to\":\"cf-nel\",\"max_age\":604800}"
                      "Connection" "close"  "cf-cache-status" "DYNAMIC"  "CF-RAY" "8fedb5dbee3cebbe-SEA"

                      ;; ... more stuff ...
                      "Cache-Control" "public, max-age=0, must-revalidate")
            :orig-content-encoding "gzip"  :status 200
            :length 0  :body   :trace-redirects ())
```


## Group-By {#group-by}

The amazing `group-by` function allows you to **group data by a common
key**. My use case for this was grouping articles in different
languages collected over time. Here's what the incoming data looked
like:

```clojure
{:count 260, :hour 2025-01-07T21:00, :language "bn"}
{:count 100, :hour 2025-01-07T21:00, :language "de"}
{:count 1041, :hour 2025-01-07T21:00, :language "es"}
{:count 211, :hour 2025-01-07T21:00, :language "fa"}
{:count 1, :hour 2025-01-07T21:00, :language "fi"}
{:count 268, :hour 2025-01-07T21:00, :language "fr"}
{:count 63, :hour 2025-01-07T21:00, :language "gu"}
;; ... data truncated ...
```

Here is how the data looks after using **group-by**:

```clojure
(group-by :language (db/get-items-by-hour-72h-langs))

{"nl" [{:count 3, :hour #object[java.time.LocalDateTime 0x2e063d23 "2025-01-07T21:00"], :language "nl"}
       {:count 2, :hour #object[java.time.LocalDateTime 0x5080c1d3 "2025-01-09T11:00"], :language "nl"}
       {:count 1, :hour #object[java.time.LocalDateTime 0x2cef6527 "2025-01-09T21:00"], :language "nl"}],
 "pt" [{:count 188, :hour #object[java.time.LocalDateTime 0x6e9352c2 "2025-01-07T21:00"], :language "pt"}
       {:count 175, :hour #object[java.time.LocalDateTime 0x41f9af3f "2025-01-08T11:00"], :language "pt"}
       {:count 62, :hour #object[java.time.LocalDateTime 0x71df170a "2025-01-09T15:00"], :language "pt"}
       {:count 96, :hour #object[java.time.LocalDateTime 0x58aa8fa8 "2025-01-09T21:00"], :language "pt"}],
 "en" [{:count 4412, :hour #object[java.time.LocalDateTime 0x74f18d18 "2025-01-07T21:00"], :language "en"}
       {:count 2552, :hour #object[java.time.LocalDateTime 0x3fd9a0d6 "2025-01-09T11:00"], :language "en"}
       {:count 227, :hour #object[java.time.LocalDateTime 0x6fa4cc34 "2025-01-09T13:00"], :language "en"}
       {:count 856, :hour #object[java.time.LocalDateTime 0x4a64b22a "2025-01-09T21:00"], :language "en"}],
 "ur" [{:count 100, :hour #object[java.time.LocalDateTime 0x552a7e60 "2025-01-07T21:00"], :language "ur"}
;; ... data truncated ...
```


## Caching Return Values (Memoization) {#caching-return-values--memoization}

We can use [core.memoize](https://cljdoc.org/d/org.clojure/core.memoize/1.1.266/doc/using-core-memoize) to cache values with a variety of methods.

```clojure
(defn get-72h-data []
  (let [data (c/extract-series {:x :hour :y :count} (db/get-items-by-hour-72h))
        series {"Collected Items" [(map #(localDateTime->Date %) (:x data)) (:y data)]}]

    series))

(def one-minute-in-ms (* 60 1000))
(def get-72h-data-memoized (memo/ttl get-72h-data {} :ttl/threshold one-minute-in-ms))
```

By calling the variable we have defined, we can see the dramatic
reduction in time on the second execution.

```clojure
(time (get-72h-data-memoized)) ; => "Elapsed time: 17.726885 msecs"
(time (get-72h-data-memoized)) ; => "Elapsed time: 0.05838 msecs"
```

-   [core.cache - Github](https://github.com/clojure/core.cache/wiki/TTL)


## HTML - Reading, Transforming, Templating {#html-reading-transforming-templating}

-   [Hickory](https://github.com/clj-commons/hickory) can transform HTML to Hiccup
-   [Hiccup](https://github.com/weavejester/hiccup) or [Rum](https://github.com/tonsky/rum) transforms Clojure to HTML
-   <https://tonsky.me/blog/hiccup/>


## Tranforming Dart {#tranforming-dart}

-   [ClojureDart](https://github.com/Tensegritics/ClojureDart) can compile Clojure(Dart) to Dart code
-   [DartClojure](https://github.com/D00mch/DartClojure) can transform Dart code to Clojure(Dart)


## Rendering Charts {#rendering-charts}

Here's a short guide on one method of many to render charts in web
apps. The Apache `echarts` library has a [getting started](https://echarts.apache.org/handbook/en/get-started/#) graph we can
use as an example.

```clojure
(defn get-72h-echart-body []
  (log/debug "Attempting to return HTML for new EChart")
  (parser/render-file "graphs/72h-echart.html"
                      {:width 800
                       :height 500
                       :data {:title {:text "ECharts Getting Started Example"}
                              :tooltip {}
                              :legend {:data ["sales"]}
                              :xAxis {:data ["Shirts" "Cardigans" "Chiffons" "Pants" "Heels" "Socks"]}
                              :yAxis {}
                              :series [{:name "Sales" :type "bar" :data [5 20 36 10 10 20]}]}}))
```

Using Selmer with the template below yields the same chart as the one
in the demo.

```html
<h3>72h Echart</h3>
<div id="72h-echart-main" style="width: {{ width }}px; height: {{ height }}px;"></div>
<script type="text/javascript">
  // Initialize the echarts instance based on the prepared dom
  var myChart = echarts.init(document.getElementById('72h-echart-main'));

  // Specify the configuration items and data for the chart
  var option = {{ data|json|safe }};

  // Display the chart using the configuration items and data just specified.
  myChart.setOption(option);
</script>
```

I realized that this library is fairly popular in the Clojure
community _after_ discovering it myself, and for good reason - using
Echarts is a highly data-driven experience that requires only a touch
of client javascript and can otherwise be entirely created with Clojure
data structures. Here are some other places Apache Echarts are used:

1.  [Scicloj - Noj notebooks](https://scicloj.github.io/noj/noj_book.echarts.html)
    -   Including a good [stacked bar chart example](https://scicloj.github.io/noj/noj_book.echarts.html#stacked-bar-chart)


# HTMX and Simple Web Applications {#htmx-and-simple-web-applications}

Using [HTMX](https://htmx.org/) provides a myriad of benefits and few drawbacks.

-   HTML is quite powerful on its own - maximally leverage these features
-   Claims to require 30% of the codebase size vs React
-   Enables any element to make an http request by click, time, etc.

You do need to write a backend that returns html, as text, and not
JSON. The benefit of this - you don't need to spend an additional few
steps transforming and interpreting JSON on your frontend.


## Useful Snippets {#useful-snippets}

Load and swap out something small, like a clock, every second:

```html
<span hx-get="/api/now" hx-trigger="load, every 1s" hx-swap="innerHTML"></span>
```

On the backend, this is the code - essentially we just send back some
text in a `span`.

```clojure
["/now"
 {:get {:summary "returns the current time as a span"
        :responses {200 {:body string?}}
        :headers {"Content-Type" "text/html"}
        :handler (fn [_params]
                   {:status 200
                    :body (str "<span>" (time/dateline-utc) "</span>")})}}]
```


## Edge Cases {#edge-cases}

**Notably** on `hx-swap` any scripts included on a page won't run, but those
included during an `hx-get` will be as long as they **aren't in the root**
in which case they will be commented out. _I learned this the hard way._

```html
<!-- *None* of these will run if a page is just swapped in. -->
<div>
  <script>console.log("in a div, this runs.");</script>
</div>

<span>
  <script>console.log("in a span, this runs.");</script>
</span>

<script>console.log("outside, this runs.");</script>
```


# Notes: Clojure for the Brave and True + {#notes-clojure-for-the-brave-and-true-plus}

This is a good Clojure textbook. The sections below are roughly the
same as the book, but are rearranged and include extra material where
I found it useful in my learning journey. The **PLUS** (`+`) indicates
this - that I have taken liberty to include additional info where I
wanted.

-   [Table of Contents](https://www.braveclojure.com/clojure-for-the-brave-and-true/)
-   [Environment Setup](https://www.braveclojure.com/getting-started)
-   [Language Fundamentals](https://www.braveclojure.com/do-things)
-   [Advanced Topics](https://www.braveclojure.com/concurrency)
-   [Back Matter](https://www.braveclojure.com/appendix-a)

All quotes in this section are from this material.


## Chapter 3: Do Things {#chapter-3-do-things}

[Do Things: A Clojure Crash Course](https://www.braveclojure.com/do-things/)

Clojure uses the familiar LISP S-Expressions. Literals are valid
forms - each of these will just return itself. All of these types
build off common Java primitives and data structures.

```clojure
1
"a string"
["a" "vector" "of" "strings"]
{ :a "map" :of "stuff"}
```

| 1                             |
|-------------------------------|
| "a string"                    |
| ["a" "vector" "of" "strings"] |
| {:a "map", :of "stuff"}       |

> Clojure uses whitespace to separate operands, and it **treats commas as
> whitespace**.

Good old s-expressions:

```clojure
(operator operand1 operand2 etc)
```

> Clojure’s structural uniformity is probably different from what you’re
> used to. In other languages, different operations might have different
> structures depending on the operator and the operands. For example,
> JavaScript employs a smorgasbord of infix notation, dot operators, and
> parentheses. Clojure’s structure is very simple and consistent by
> comparison. [...] **No matter which operator you’re using or what kind
> of data you’re operating on, the structure is the same**.


### Control Flow {#control-flow}

**Key Functions:**

-   [clojure.core/if](https://clojuredocs.org/clojure.core/if)
-   [clojure.core/cond](https://clojuredocs.org/clojure.core/cond)
-   [clojure.core/when](https://clojuredocs.org/clojure.core/when)
-   [clojure.core/when-not](https://clojuredocs.org/clojure.core/when-not)
-   [clojure.core/do](https://clojuredocs.org/clojure.core/do)

<!--listend-->

```clojure
(def boolean-value true)
(if boolean-value "It's true!" "Lol nope") ; "It's true!"
(when boolean-value "Yes") ; "Yes"
(when-not boolean-value "Nope")
```

**When** and **when-not** enable execution of a form when a value is true (or
false for when-not) without providing a false-case like an if statement.

**Do** enables the combination of multiple forms - it will return the
result of the final form. This is very useful for logging or running
multiple simple statements within an **if** expression.

```clojure
(do (+ 1 2) (+ 3 4) (+ 5 6))
```

```text
11
```


### Boolean Mathematics &amp; Truthiness {#boolean-mathematics-and-truthiness}

**Key concepts:**

-   `nil` and `false` are both interpreted as false
-   all other values are interpreted as true
-   **Operators:**
    -   [clojure.core/=](https://clojuredocs.org/clojure.core/=)
    -   [clojure.core/nil?](https://clojuredocs.org/clojure.core/nil_q)
    -   [clojure.core/true?](https://clojuredocs.org/clojure.core/true_q)
    -   [clojure.core/false?](https://clojuredocs.org/clojure.core/false_q)
    -   [clojure.core/or](https://clojuredocs.org/clojure.core/or)
    -   [clojure.core/and](https://clojuredocs.org/clojure.core/and)
    -   [clojure.core/not](https://clojuredocs.org/clojure.core/not)

<!--listend-->

```clojure
(nil? 1)       ;; => false
(nil? nil)     ;; => true
(true? true)   ;; => true
(false? true)  ;; => false
(true? nil)    ;; => false - nil is falsey
```

**Or** returns the first truthy value or the last value:

```clojure
(or nil false :cry :rage :fight :death)
```

```text
:cry
```

**And** returns the first falsey value or the last truthy value:

```clojure
(and true 123 :kick :drown false)
```

```text
false
```


### Assignments {#assignments}

Use [clojure.core/def](https://clojuredocs.org/clojure.core/def) to bind names in Clojure.

> Notice that I’m using the term **bind**, whereas in other languages you’d
> say you’re assigning a value to a variable. Those other languages
> typically encourage you to perform multiple assignments to the same
> variable.
>
> However, changing the value associated with a name like this can make
> it harder to understand your program’s behavior because it’s more
> difficult to know which value is associated with a name or why that
> value might have changed. Clojure has a set of tools for dealing with
> change, which you’ll learn about in Chapter 10. As you learn Clojure,
> you’ll find that you’ll rarely need to alter a name/value association.

```clojure
(def status :my-body-is-ready)
```

```text
#'org.core/status
```


### Types {#types}

```clojure
{:numbers [ 1 2/3 4.5 ]
 :strings ["Yep" "With escapes! -> \""] }
```

|          |             |          |                             |
|----------|-------------|----------|-----------------------------|
| :numbers | (1 2/3 4.5) | :strings | (Yep With escapes! -&gt; ") |

```clojure
:keywords
'symbols
```


### Primitive Data Structures (Collections) {#primitive-data-structures--collections}

Clojure supports four [literal collection](https://clojure.org/guides/learn/syntax#_literal_collections) types:

```clojure
'(1 2 3)     ; list
[1 2 3]      ; vector
#{1 2 3}     ; set
{:a 1, :b 2} ; map
```

**Maps**

[clojure.core/get](https://clojuredocs.org/clojure.core/get) allows you to grab keys, and can return nil or a default:

```clojure
(get {:x 1 :y 2} :y)   ;; => 2
(get {:x 1 :y 2} :z)   ;; => nil
(get {:x 1 :y 2} :z 3) ;; => 3
```

[clojure.core/get-in](https://clojuredocs.org/clojure.core/get-in) allows you to dig into nested maps:

```clojure
(get-in
  {:head 1 :chest {:ribs 10 :cavity {:heart "pumpin'" :lungs 2}}}
  [:chest :cavity :heart])
```

```text
pumpin'
```

You can use a map like a function:

```clojure
({:what "in" :tar "nation?"} :tar)
```

```text
nation?
```

...and **keywords** can be used the same way with a few data structures:

```clojure
(:tar {:what "in" :tar "nation?"})
```

```text
nation?
```

```clojure
(:far {:what "in" :tar "nation?"} "no far")
```

```text
no far
```

**Vectors** - [clojure.core/vec](https://clojuredocs.org/clojure.core/vec)

Vectors are zero-indexed collections like arrays.

```clojure
(def vec1 [1 2 3 4 5])
(get vec1 0) ;; => 1
```

You can use **vector** to make vectors and **conj** to add to them:

```clojure
(def vec2 (vector :weather :is :nice))
(conj vec2 :today) ;; => [:weather :is :nice :today]
```

**Lists** - [clojure.core/list](https://clojuredocs.org/clojure.core/list)

Recall that Clojure is a LISP. Lists can hold anything. Use a tick
mark to indicate that a sexp is a list.

```clojure
(def list1 '(1 2 3 4 5))
(nth list1 3)  ;; => 4
```

Using [clojure.core/conj](https://clojuredocs.org/clojure.core/conj) on a list adds items to the **beginning**, and on
a vector will add items to the **end**. A bit of a footgun.

```clojure
(conj list1 0) ;; => (0 1 2 3 4 5)
```

**Hash Sets** and **Sorted Sets**

[Brave Clojure: Sets](https://www.braveclojure.com/do-things/#Sets)

```clojure
(def hs1 #{"this is a hash-set" 19 :testing})
```

A hash set can only store **unique values**. Using **conj** to add to a
hash-set will combine unique values.

```clojure
(conj hs1 19)
```

```text
#{"this is a hash set" 19 :testing}
```

```clojure
(hash-set 1 2 3 4 1 2 3 4 5 6)
```

```text
#{1 4 6 3 2 5}
```

Usefully, **set** can be used to derive all the unique values from another
collection.

```clojure
(set [1 2 3 4 1 2 3 3 4 1 2 3 4 2 3 2 1 2])
```

```text
#{1 4 3 2}
```

Use [clojure.core/get](https://clojuredocs.org/clojure.core/get) and [clojure.core/contains?](https://clojuredocs.org/clojure.core/contains_q) with hash sets:

```clojure
(contains? hs1 18) ; false
(contains? hs1 19) ; true
(get hs1 18) ;; => nil
(get hs1 19) ; 19
```


### Calling Functions {#calling-functions}

Because of Clojure's Lisp syntax, with the humble and incredibly
simple s-expression as the core building block of a Lisp program, we
can do some pretty incredible things to simplify complex operations.

```clojure
(operator operand operand operand)
```

> "**All Clojure operations have the same syntax**: opening
> parenthesis, operator, operands, closing parenthesis"
>
> -- Daniel Higginbotham[^fn:1]

Also recall that we can return functions:

```clojure
(or + - * /)
```

```text
#function[clojure.core/+]
```

Which means we can return a function and call it on more data:

```clojure
((or + -) 1 2 3)
```

```text
6
```

The error `cannot be cast to clojure.lang.IFn` indicates you are trying
to use a number, string, or other type as a function.

```clojure
("why" 1 2 3)
```

```text
class java.lang.String cannot be cast to class clojure.lang.IFn
```

Also see **macro calls** and **special forms**.

> Clojure has no privileged functions. + is just a function, - is just a
> function, and inc and map are just functions. They’re no better than
> the functions you define yourself. So don’t let them give you any lip!
> More important, this fact helps demonstrate Clojure’s underlying
> simplicity. In a way, Clojure is very dumb. When you make a function
> call, Clojure just says, “map? Sure, whatever! I’ll just apply this
> and move on.” It doesn’t care what the function is or where it came
> from; it treats all func- tions the same. At its core, Clojure doesn’t
> give two burger flips about addi- tion, multiplication, or mapping. It
> just cares about applying functions.
>
> -- Daniel Higginbotham[^fn:1]


### Defining Functions {#defining-functions}

```clojure
(defn my-function
  "This is a docstring (yes, a JavaDoc docstring) to explain the function."
  [a b c]    ; <-- parameters
  (+ a b c))
```

```text
#'org.core/my-function
```

```clojure
(my-function 1 2 3)
```

```text
6
```

Above is a simple example of `defn`, the function definition macro. A
function must be defined with zero or more arguments and at least one
clause in the function body. There are a few different ways to define
a function that takes multiple arguments.

[clojure.core/defn](https://clojuredocs.org/clojure.core/defn)

**Anonymous Functions**

For one-offs or _lambdas_ you can use [clojure.core/fn](https://clojuredocs.org/clojure.core/fn). The extra space
below is only present to highlight where the function is defined.

```clojure
( (fn [x] (* x 2))  4)
```

```text
8
```

Even more condensed syntax exists to accomplish the same purpose.

```clojure
( #(* % 2)  4)
```

```text
8
```

Here, `%` is used to represent the first argument to a function. If you
need multiple arguments you can use `%1`, `%2`, `%3`, or `%&` for rest.

**Multi Arity Functions**

```clojure
(defn hello
  "Provides a greeting to the user."
  ([name]
   (str "Hello, " name " - Welcome!"))
  ([name prefix]
   (str "Hello " prefix " " name))
  ([name prefix suffix]
   (str "Hello " prefix " " name ", " suffix "!")))
```

```text
#'org.core/hello
```

```clojure
(hello "Ryan")
```

```text
"Hello, Ryan - Welcome!"
```

```clojure
(hello "Ryan" "Mr." "Master of Ceremonies")
```

```text
"Hello Mr. Ryan, Master of Ceremonies!"
```

Providing a number of function bodies given different arguments is an
easy way to group a similar collection of functions behind one name.

**Variable Arity Functions**

An ampersand (`&`) stores the remainder of arguments in a list.

```clojure
(defn show_rest
  [first & rest_of_args]
  (str "First: " first " + rest: " rest_of_args))
```

```text
#'org.core/show_rest
```

```clojure
(show_rest 1 2 3 4)
```

```text
"First: 1 + rest: (2 3 4)"
```

**Multimethods**

A **multimethod** enables a programmer to run an initial function against
some data to determine which function it should eventually be passed
to.

-   [clojure.core/defmulti](https://clojuredocs.org/clojure.core/defmulti)
-   [clojure.core/getmethod](https://clojuredocs.org/clojure.core/getmethod)

<!--listend-->

```clojure
(defmulti get-dose
  "With weight in Kg, provide the adult dose of a medicine."
  (fn [data] (:medicine data)))

(defmethod get-dose :ibuprofen
  [data]
  (str "Up to " (* (:weight data) 10) "mg / 4hr"))

(defmethod get-dose :acetominophen
  [data]
  (str "Up to " (* (:weight data) 5) "mg / 4hr"))
```

```clojure
(get-dose {:medicine :ibuprofen :weight 200})
```

```text
"Up to 2000mg / 4hr"
```

```clojure
(get-dose {:medicine :acetominophen :weight 200})
```

```text
"Up to 1000mg / 4hr"
```


### Destructuring {#destructuring}

To _destructure_ is to pull data out of a data structure within the
arguments of a function. This is one of the really magical things I
enjoyed when first learning [Elixir](/elixir/). It saves a lot of time and
prevents the first few lines of a function being full of `first`,
`get-in`, etc.

```clojure
(defn second-thing [[a b]] b)
```

```clojure
(second-thing [1 2 3])
```

```text
2
```

...as you can see, the exact length of the vector is not strictly
pattern-matched, but the first two arguments are captured and
available in the function as arguments. You can use `& rest` in this
destructuring syntax to get the remainder of arguments.

For **maps**, these formats are equivalent:

```clojure
[{key1 :key1 key2 :key2}]
[{:keys [key1 key2]}]
```

You can use the `:as` key to also make the entire vector/map available.

```clojure
[{key1 :key1 key2 :key2 :as data}]
[{:keys [key1 key2] :as data}]
[[a b :as data]]
```

```clojure
(defn test1 [{key1 :key1 key2 :key2 :as mapdata} [a b :as vecdata]]
  (str "Map: " mapdata " - Vec: " vecdata))
```

```clojure
(test1 {:key1 "wow" :key2 "whoa"} [:first :second :third :fourth])
```

```text
"Map: {:key1 \"wow\", :key2 \"whoa\"} - Vec: [:first :second :third :fourth]"
```

These approaches can also be heavily nested. If there is a map within
a list that contains a map, this can be destructured.

-   See this [Clojure destructuring cheatsheet](https://gist.github.com/john2x/e1dca953548bfdfb9844)


### Closures {#closures}

Functions that are returned from other functions with encapsulated
data are called _closures_.

```clojure
(defn declare-pilled
  "Returns a string generator stating that the input is thing-pilled"
  [thing]
  (fn [x] (str "Wow, " x " sure is " thing "pilled.")))
```

```clojure
(def that-is-cringe (declare-pilled "cringe"))
```

```clojure
(that-is-cringe "watching TV")
```

```text
"Wow, watching TV sure is cringepilled."
```

> Did you pick the name based on starting with the word "closure" and
> replacing the "s" with "j" for Java? It seems pretty likely, but it
> would be nice to have that confirmed.
>
> The name was chosen to be unique. I wanted to involve c (c#), l (lisp)
> and j (java). Once I came up with **Clojure**, given the pun on closure,
> the available domains and vast emptiness of the googlespace, it was an
> easy decision.
>
> -- Rich Hickey[^fn:12]


### Binding Variables {#binding-variables}

You can use [clojure.core/let](https://clojuredocs.org/clojure.core/let) like `let*` from _elisp_. It allows you to
**bind** variables within its lexical scope - a fancy way of stating
'within the structure that it was created inside'.

```clojure
(let [a 1
      b 2]

  (+ a b))
```

```text
3
```


### Loops and Recursion {#loops-and-recursion}

Far more often you'll be using **map**, **filter**, and **reduce** to perform
operations on an array, but Clojure includes a **loop/recur** construct to
improve the performance of what otherwise would be a very standard
inner and outer pair forming a recursive function.

See [clojure.core/loop](https://clojuredocs.org/clojure.core/loop) and [clojure.core/recur](https://clojuredocs.org/clojure.core/recur).

```clojure
(loop [i 0
       list []]
  (if (< i 10)
    (recur (+ i 1)
           (conj list i))
    list))
```

```text
[0 1 2 3 4 5 6 7 8 9]
```

Looking closely, you'll see these two important statements:

**First** - `loop` works like a `let` and enables the definition of initial
variables. In this case, `i` is set to `0` and `list` holds an empty list.

```clojure
(loop [i 0
       list []]
```

**Second** - the `recur` statement kicks execution back up to the beginning
of the `loop` with the provided elements as the new

```clojure
(recur (+ i 1)         ; bound to 'i'
       (conj list i))  ; bound to 'list'
```

Using `loop` is a cleaner and more performant approach to writing loops
than recursion as used in traditional functional languages.


### Map, Filter, Reduce {#map-filter-reduce}

The three kings of list processing methods. _Learn to use them and
profit!_

```clojure
(map (fn [x] (* x 2)) [1 2 3 4 5 6])
```

```text
(2 4 6 8 10 12)
```

```clojure
(filter (fn [x] (> x 7)) [2 4 6 8 10 12])
```

```text
(8 10 12)
```

```clojure
(reduce (fn [a b] (+ a b)) [1 2 3 4 5 6])
```

```text
21
```

You may provide `reduce` with an initial value, which will be used
instead of the first two elements in the sequence.

```clojure
(reduce (fn [a b] (+ a b)) 10 [1 2 3 4 5 6])
```

```text
31
```

The `reduce` function is meant, in general, to build results. This does
not mean it has to return a single primitive. Per the book,[^fn:1] it
is clearer to use `reduce` when building a result than loop, which
forces a user to more deeply inspect your code to understand its
purpose.

```clojure
(reduce (fn [a b] {:name b :child a}) :none ["Mark" "Luke" "John"])
```

```text
{:name "John", :child {:name "Luke", :child {:name "Mark", :child :none}}}
```


## Chapter 11: Mastering Concurrent Processes {#chapter-11-mastering-concurrent-processes}

-   See [Chapter 11](https://www.braveclojure.com/core-async/) of Brave Clojure. Introduced in chapter 9.
-   Below is my personal fiddling. This section is not yet refined.

<!--listend-->

```clojure
(ns ryanfleck.chantest
  (:require [clojure.core.async :as a :refer [>! <! >!! <!! go chan buffer close! thread alts! alts!! timeout]]))

(defn wait [{time-ms :time-ms message :message key :key}]
  (println (str ">>> [" (or key "?") "] Sleeping for " time-ms "ms " (or message "")))
  (Thread/sleep time-ms)
  (println (str "<<< ["(or key "?")"] Done sleeping for " time-ms "ms"))
  (str "Slept for " time-ms "ms"))

;; From https://www.braveclojure.com/core-async/

;; Testing - start a channel and read from it with a delay.
(do
  (def input-chan (chan))

  (thread
    (println "Running a thread...")
    (doseq [x (range 5)]
      (println (str "Placing " x))
      (let [res (>!! input-chan x)]
        (if res
          (println (str "Placed " x " on channel."))
          (println "Channel was closed."))))

    (close! input-chan))

  (go (loop [] (let [res (<! input-chan)]
                 (println res)
                 (wait {:time-ms 1000 :key res})
                 (if res
                   (recur)
                   (println "Channel was closed."))))))

;; Start twenty go-routines
;; From this testing - eight are able to run at once (full thread pool)
(do
  (def input-chan (chan 100))

  (thread
    (println "Running a thread...")
    (doseq [x (range 400)]
      (println (str "Placing " x))
      (let [res (>!! input-chan x)]
        (if res
          (println (str "Placed " x " on channel."))
          (println "Channel was closed."))))

    (close! input-chan))

  (wait {:time-ms 1000 :message "Starting readers now..."})
  (doseq [_ (range 20)]
    (go (loop [] (do
                   (println )
                   (let [res (<! input-chan)]
                     (println res)
                     (wait {:time-ms 5000 :key res})
                     (if res
                       (recur)
                       (println "Channel was closed."))))))))
```


## Chapter 12: Interop with Java {#chapter-12-interop-with-java}

-   See [Chapter 12](https://www.braveclojure.com/java) of Brave Clojure
-   It is easy to reach into Java for tools and libraries.
    -   Notably the [Azure tools for Java developers](https://learn.microsoft.com/en-us/azure/developer/java/)

**Other Resources**:

-   [Stuart Halloway - Clojure Interop: A Better Java than Java](https://www.youtube.com/results?search_query=clojure+interop)
-   [Clojure.org - Java Interop](https://clojure.org/reference/java_interop)
-   [Clojure Guides - Java Interop](https://clojure-doc.org/articles/language/interop/)
-   [Eric Normand - Tricks for Java Interop](https://ericnormand.me/article/tricks-for-java-interop)


# Deployment {#deployment}

Clojure, when compared to some other platforms, is fairly easy to
deploy - both on bare metal and containerized. The JVM has been
deployed on unknowable billions of machines at this point, and its
properties are well understood.


## Docker {#docker}

Let's take a look at what it would take to get a web app called
`coolzone` up and running on your server with docker and Traefik
installed. You'll need to write a `Dockerfile` and `docker-compose.yml` to
define the container for your app and how to bring it up and network
it.

`-->` **Dockerfile**

```docker
# Run a multi-stage build
# 1. Build JAR in clojure:lein
# 2. Leave JAR in finished JRE container
FROM clojure:lein

# Create App Directory
RUN mkdir -p /app
WORKDIR /app

# Get Dependencies (Cached as long as project.clj is unchanged)
COPY project.clj /app
RUN lein deps

# Build UberJar
COPY . /app
RUN lein uberjar

# Multi-Stage Build - Run in IBM Semeru
# See: https://hub.docker.com/_/ibm-semeru-runtimes
# Logging: https://luminusweb.com/docs/logging.html
FROM ibm-semeru-runtimes:open-21-jdk

RUN mkdir /opt/app
COPY --from=0 /app/target/uberjar/coolzone.jar /opt/app
EXPOSE 3000

CMD ["java", "-jar", "/opt/app/coolzone.jar"]


```

`-->` **docker-compose.yml**

```yaml
services:
  coolzone:
    build:
      context: .
      dockerfile: "Dockerfile"
    image: coolzone_production
    env_file: "prod.env" # set environment variables here.
    restart: unless-stopped
    volumes:
      - ~/Coolzone/data:/data/files:rw
    ports:
      # external:internal
      - "7598:3000"
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.coolzone.rule=Host(`coolzone.ryanfleck.ca`)"
      - "traefik.http.services.coolzone.loadbalancer.server.port=3000"
      - "traefik.http.routers.coolzone.service=coolzone"
      # Note: Some Traefik labels removed for security.
    networks:
      - web

networks:
  web:
    external: true
```

`-->` **prod.env**

```bash
PROD="true"
PORT=3000
DATA_DIR="/data/files"
DATABASE_URL="postgresql://whatever..."
SERVICE_KEY="jlkhl76098798d5gsjero2ih-asdufoi45lsf..."
```

At this point all you need to do is pull your repository and run:

```bash
docker-compose up -d --build coolzone
```

To launch your container and troubleshoot run:

```bash
docker-compose run coolzone sh
```


# Optimization &amp; JVM Bytecode {#optimization-and-jvm-bytecode}

-   <https://dev.to/quoll/clojure-and-the-jvm-5bi9>


# Emacs {#emacs}

Emacs is my editor of choice. It has unbeatable support for LISPs.


## Setup {#setup}

My personal configuration is based off of the sensible defaults
provided in the [Clojure for the Brave and True](https://www.braveclojure.com/) textbook. Using the
initialization files mentioned on the linked page is a great way to
start using Emacs in general.

Keep in mind that the more crap you have in your classpath, the longer
CIDER will take to start up.


## Command Cheat Sheet {#command-cheat-sheet}

| Command            | Action                                             |
|--------------------|----------------------------------------------------|
| C-c C-x C-x RET    | Start CIDER                                        |
| M-x cider          | Prompts for more options                           |
| M-x cider-jack-in  | Jacks in to current Clojure (clj) project          |
| C-c C-z            | Jump cursor to REPL                                |
| C-u C-c C-z        | Jump cursor to REPL _and switch to file namespace_ |
| C-c C-d a          | cider-apropos to remember var names                |
| C-x 5 2            | Pop out buffer into new window                     |
| C-c C-k            | Evaluate buffer (handy)                            |
| C-c C-e            | Evaluate preceding form                            |
| C-c C-c _or_ C-M-x | Evaluate current top-level form                    |
| C-u C-c C-c        | Evaluate current top-level form **in debug mode**  |
| C-c C-v r          | Evaluate highlighted region                        |
| C-c C-b            | Interrupt evaluation                               |
| M-.                | cider-find-var: Warp to definition under cursor    |
| C-c C-d d          | Look up documentation for current form             |
| C-c C-m            | macroexpand-1: Macroexpand the form at point       |
| C-c M-z            | Eval current buffer and switch to relevant REPL    |
| C-c M-n r          | Reload all files on classpath                      |
| M-,                | Return to your pre-jump location                   |
| M-TAB              | Complete the symbol at point                       |
| C-c C-q            | Quit CIDER                                         |

**Sources:**

1.  [Cider Docs: Basic Workflow](https://docs.cider.mx/cider/usage/cider_mode.html#basic-workflow)
2.  Experience

{{< pagebreak >}}


## Cider {#cider}

CIDER is an interactive programming environment for Clojure.

> Traditional programming languages and development environments often
> use a Edit, Compile, Run Cycle. In this environment, the programmer
> modifies the code, compiles it, and then runs it to see if it does
> what she wants. The program is then terminated, and the programmer
> goes back to editing the program further. This cycle is repeated over
> and over until the program behavior conforms to what the programmer
> desires.
>
> Using CIDER's interactive programming environment, a programmer works
> in a very dynamic and incremental manner. Instead of repeatedly
> editing, compiling, and restarting an application, the programmer
> starts the application once and then adds and updates individual
> Clojure definitions as the program continues to run.[^fn:13]

It looks like this when run - the explanation given below is a great
introduction to much of the built-in functionality made available to
the user.

```nil
;; Connected to nREPL server - nrepl://localhost:36099
;; CIDER 1.13.0-snapshot (package: 20231127.825), nREPL 1.0.0
;; Clojure 1.11.1, Java 17.0.9
;;     Docs: (doc function-name)
;;           (find-doc part-of-name)
;;   Source: (source function-name)
;;  Javadoc: (javadoc java-object-or-class)
;;     Exit: <C-c C-q>
;;  Results: Stored in vars *1, *2, *3, an exception in *e;
;; ======================================================================
;; If you’re new to CIDER it is highly recommended to go through its
;; user manual first. Type <M-x cider-view-manual> to view it.
;; In case you’re seeing any warnings you should consult the manual’s
;; "Troubleshooting" section.
;;
;; Here are a few tips to get you started:
;;
;; * Press <C-h m> to see a list of the keybindings available (this
;;   will work in every Emacs buffer)
;; * Press <,> to quickly invoke some REPL command
;; * Press <C-c C-z> to switch between the REPL and a Clojure file
;; * Press <M-.> to jump to the source of something (e.g. a var, a
;;   Java method)
;; * Press <C-c C-d C-d> to view the documentation for something (e.g.
;;   a var, a Java method)
;; * Print CIDER’s refcard and keep it close to your keyboard.
;;
;; CIDER is super customizable - try <M-x customize-group cider> to
;; get a feel for this. If you’re thirsty for knowledge you should try
;; <M-x cider-drink-a-sip>.
;;
;; If you think you’ve encountered a bug (or have some suggestions for
;; improvements) use <M-x cider-report-bug> to report it.
;;
;; Above all else - don’t panic! In case of an emergency - procure
;; some (hard) cider and enjoy it responsibly!
;;
;; You can remove this message with the <M-x cider-repl-clear-help-banner> command.
;; You can disable it from appearing on start by setting
;; ‘cider-repl-display-help-banner’ to nil.
;; ======================================================================
```


## Manual Editing Suite: Emacs, Ox-Hugo, Cider {#manual-editing-suite-emacs-ox-hugo-cider}

There is some setup required to execute Clojure inline within this
org-mode file and cleanly transform it to markdown.

[Ox-Hugo](https://ox-hugo.scripter.co/) must be added to Emacs.

There is a minimal amount of emacs lisp added to my editor to support
this. The remainder of setup is completed in the front matter of the
org file, `clj.org`, in `/content-org/languages/clj.org`.

```elisp
(setup (:package ox-hugo)
  (:load-after ox))

(defun clojuredoc-string-to-url    (str)
    "In a url, ? becomes _q, replace these in the url part of STR in clojuredocs links."
   (s-replace "?" "_q" str))

(defun org-link-to-clojuredocs ()
  "Insert a link to clojuredocs.org."
  (interactive)
  (let ((str (read-string "Function (ex. clojure.core/when) >> ") ))
    (insert (s-concat "[[https://clojuredocs.org/"
                      (clojuredoc-string-to-url str) "][" str "]]"))))

(defun org-link-to-core-clojuredocs ()
  "Insert a link to clojuredocs.org in the clojure.core namespace."
  (interactive)
  (let ((str (read-string "clojure.core function (ex. when) >> ") ))
    (insert (s-concat "[[https://clojuredocs.org/clojure.core/"
                      (clojuredoc-string-to-url str) "][clojure.core/" str "]]"))))

;; Make these easier to type
(global-set-key (kbd "C-c o C") 'org-link-to-clojuredocs)
(global-set-key (kbd "C-c o c") 'org-link-to-core-clojuredocs)
```

A bunch of additional front matter must be added in order for **ox-hugo**
to correctly move the file and add the appropriate front matter. Care
has been taken to ensure the [output format](https://orgmode.org/worg/org-contrib/babel/header-args.html) is readable.

```org
#+LAYOUT: docs-manual
#+TITLE: Clojure
#+SUMMARY: Enterprise grade magick.
#+hugo_base_dir: ../../
#+hugo_section: languages
#+hugo_custom_front_matter: :warning "THIS FILE WAS GENERATED BY OX-HUGO, DO NOT EDIT!!!"
#+hugo_custom_front_matter: :toc true :summary "Enterprise grade magick." :chapter true
#+hugo_custom_front_matter: :aliases '("/clj/" "/clojure/" "/clj" "/cljd" "/cljs")
#+PROPERTY: header-args :eval no :exports both
#+hugo_level_offset: 0
```

...apart from an issue where I can't have headers beyond level 3,
which I still must resolve, **ox-hugo** has happily enabled me to leverage
all the enhanced markdown processing features provided by hugo (render
hooks in particular) while still writing and executing code in ORG.


# Obligatory Bell Curve Meme {#obligatory-bell-curve-meme}

As an ex-React, ex-Django, ex-Typescript, ex-Express developer, happy
to never return unless a good reason / cool project emerges, I am
fully qualified to throw all this shade. The technologies clowned upon
below all have their place, but due to their popularity and ease of
ChatGPT'ing together codebases, are prone to turning into a strange
sort of insecure muck.

{{< figure src="/clj/bell-curve-clojure.png" >}}

Despite all the advantages of LISPs, wonderful systems are regularly
built in a variety of languages. The JVM is **not** a good fit for many
applications. Clojure is great, but don't be a forceful evangelist or
you'll end up like the guy in the middle of this meme. It's the worst
type of programmer you could be.

Good programming is a certain mindset and wisdom - not a language.


# Resources {#resources}

**Websites:**

1.  [Clojure for the Brave and True](https://www.braveclojure.com/)
2.  [Clojure on Exercism (Challenges)](https://exercism.org/tracks/clojure/)
3.  [Luminus (Web 'Framework')](https://luminusweb.com/)
4.  [Clojure Job Board](https://jobs.braveclojure.com/)
5.  [Clojure Regex Tutorial](https://ericnormand.me/mini-guide/clojure-regex)
6.  [Newest 'Clojure' Questions on Stack Overflow](https://stackoverflow.com/questions/tagged/clojure?tab=Newest)
7.  [Clojure on Stack Overflow](https://stackoverflow.com/tags/clojure/info)
8.  [Clojure Slack Channel](https://app.slack.com/client/T03RZGPFR/C03S1KBA2)
9.  [Org-Babel Clojure (Literate Programming)](https://orgmode.org/worg/org-contrib/babel/languages/ob-doc-clojure.html) and [(use case - try out libraries)](https://ag91.github.io/blog/2023/08/03/an-easier-way-to-try-out-clojure-libraries-with-ob-clojure-and-cider/)
10. [Quil: Animations in Clojure](http://quil.info/)
11. [SciCloj - Clojure Data Science Community](https://scicloj.github.io/), and their [Noj](https://scicloj.github.io/noj/) project

**Books:**

(Remember to **buy** books to _support good authors_.)

1.  [Dmitri
    Sotnikov, Scot Brown: **Web Development with Clojure: Build Large,
    Maintainable Web Applications Interactively**, 3e, 2021, ISBN:
    168050682X, 9781680506822](https://libgen.is/book/index.php?md5=77F8623AAE8E49C9EE936E406FE7B1DF)
2.  [Renzo
    Borgatti: **Clojure, The Essential Reference**, 0e, 2021, ISBN:
    9781617293580, 6664843499, 1447772004, 161729358X](https://libgen.is/book/index.php?md5=FD806788B6664843499C2AAF3309E5CB)
3.  [Kleppmann,
    Martin: **Designing data-intensive applications: the big ideas behind
    reliable, scalable, and maintainable systems**, 1e2p, ISBN:
    9781449373320, 1449373321](https://libgen.is/book/index.php?md5=41D80961BA66DA6A1294AA9624CEA15D)

[^fn:1]: "Clojure for the Brave and True" by Daniel Higginbotham, [braveclojure.com](https://www.braveclojure.com/)
[^fn:2]: "A History of Clojure", Rich Hickey, [dl.acm.org PDF](https://dl.acm.org/doi/pdf/10.1145/3386321)
[^fn:3]: "Companies using Clojure or ClojureScript" [clojure.org](https://clojure.org/community/companies)
[^fn:4]: "The Curse of Lisp - Clojure vs Lisp" <https://www.freshcodeit.com/blog/myths-of-lisp-curse#clojure-vs-lisp-acquired-and-inherited-traits>
[^fn:5]: "Literate Programming", Donald E. Knuth, [stanford.edu](https://www-cs-faculty.stanford.edu/~knuth/lp.html)
[^fn:6]: "Clojure for the Brave and True" page 48.
[^fn:7]: "How to use ASDF on MacOS", Qing Wu, [wiserfirst.com](https://www.wiserfirst.com/blog/how-to-use-asdf-on-macos/)
[^fn:8]: "Introducing the no-cost IBM Semeru Runtimes", Mark Stoodley, [developer.ibm.com](https://developer.ibm.com/blogs/introducing-the-ibm-semeru-runtimes/)
[^fn:9]: "Docker Hub: IBM Semeru Runtimes", [hub.docker.com](https://hub.docker.com/_/ibm-semeru-runtimes)
[^fn:10]: "Technology Compatibility Kit", [wiki](https://en.wikipedia.org/wiki/Technology_Compatibility_Kit)
[^fn:11]: "The Definitive Guide to Clojure on the JVM", Eric Normand, [ericnormand.me](https://ericnormand.me/guide/clojure-jvm#amazon-corretto)
[^fn:12]: "Why is Clojure named Clojure?", Alex K., [stackoverflow.com](https://stackoverflow.com/questions/6427128/why-is-clojure-named-clojure)
[^fn:13]: Documentation for [CIDER: Interactive Programming](https://docs.cider.mx/cider/usage/interactive_programming.html)



> Thank you for reading!  
> Find more content at <https://manuals.ryanfleck.ca/>  
> Source page: <https://manuals.ryanfleck.ca/clj/>  
> Site index: [llms.txt](https://manuals.ryanfleck.ca/llms.txt)