Let Over Hiccup: Creating Closures with Reagent
Tags: clojure, react, webdev, lisp
Published: 2020-11-23 18:00:07

> Sometimes it's called a _closure_, other times a saved lexical environment. Or, as some of us like to say, _let over lambda_.
> — [Let Over Lambda](https://letoverlambda.com/), [Chapter 2: Closures](https://letoverlambda.com/index.cl/guest/chap2.html#sec_5).

## λ
When I started to learn [Reagent](https://github.com/reagent-project/reagent), I noticed a familiar pattern in [form-2](https://purelyfunctional.tv/guide/reagent/) components that use a let binding to return a lexical closure, an idiom that [Doug Hoyte](https://github.com/hoytech) elegantly calls **let over lambda** in his book of the same title:
{% gist https://gist.github.com/boolpath/8ea2b3080a858dfad0714f93a2621449 file=form-2-component.cljs %}

> "Let over lambda is a nickname given to a lexical closure. [...] In a let over lambda scenario, the last form returned by a _let_ statement is a _lambda_ expression. It literally looks like _let_ is sitting on top of _lambda_."

{% gist https://gist.github.com/boolpath/8ea2b3080a858dfad0714f93a2621449 file=let-over-lambda-pattern.lisp %}

> "Sometimes the most valuable thing to have a let form return is an anonymous function which takes advantage of the lexical environment supplied by the _let_ form. To create these functions in lisp we use _lambda_."

---

As Hoyte explains, "one way of thinking about closures is that they are **functions with state**". In Common Lisp, this pattern can be used to create a counter by surrounding a `lambda` expression with a `let` form:
{% gist https://gist.github.com/boolpath/8ea2b3080a858dfad0714f93a2621449 file=let-over-lambda.lisp %}

This expression returns a function that increments the `counter` variable every time it is called. In Clojure, anonymous functions can be created using the `fn` special form that is analogous to Common Lisp's `lambda`: 

{% gist https://gist.github.com/boolpath/8ea2b3080a858dfad0714f93a2621449 file=let-over-lambda.clj %}

In Reagent, the simplest form of a let over lambda would create a similar let binding, but using `reagent.core/atom` instead of `clojure.core/atom` so that Reagent can watch for and re-render the component on state changes:

{% gist https://gist.github.com/boolpath/8ea2b3080a858dfad0714f93a2621449 file=let-over-lambda.cljs %}

However, here the inner function would be called only when rendering the component for the first time, but nothing would be able to access or increment the value of `counter` and thus trigger the component to re-render.

Let's modify the last snippet to return a [Hiccup](https://github.com/weavejester/hiccup) vector that describes an HTML button, adds an event listener that increments the `counter` on every click, and contains a child expression that dereferences the `counter`:

{% gist https://gist.github.com/boolpath/8ea2b3080a858dfad0714f93a2621449 file=let-over-hiccup-lambda.cljs %}

This closure will remember the number of times that the button has been clicked. After being initialized with a value of `0`, the value of `counter` will be incremented by `1` every time the `#(swap! counter inc)` function is called.

Finally, let's turn this button into an actual component with state by using the above way of creating closures with Reagent. But in order to create such closures _as needed_, we must define a function that returns a let over lambda: 

{% gist https://gist.github.com/boolpath/8ea2b3080a858dfad0714f93a2621449 file=lambda-over-let-over-lambda.lisp %}

Coincidentally, this pattern used to create Reagent components with state is exactly what Hoyte calls "lambda over let over lambda". That is, **form-2 components follow the lambda over let over lambda pattern:**

{% gist https://gist.github.com/boolpath/8ea2b3080a858dfad0714f93a2621449 file=lambda-over-let-over-hiccup-lambda.cljs %}

Thus, every time `create-counter-button` is called, a new closure will be created to store the state of the new button in it's own lexical environment. It's amazing that this can be accomplished without objects and classes at all!

> Let and lambda are fundamental; objects and classes are derivatives. As Steele says, the "object" need not be a primitive notion in programming languages. — [Let Over Lambda](https://letoverlambda.com/), [Chapter 2](https://letoverlambda.com/index.cl/guest/chap2.html#sec_5).

## Conclusion
Much like "let over lambda is a nickname given to a lexical closure", we can say that **Let Over Hiccup** is a nickname for a closure that returns a Hiccup vector, regardless of how many layers of let over lambdas and nested components there will be in more sophisticated compositions.

I think it's very interesting and surprising that a simple example of a Reagent component uses a pattern that gives its name to an advanced book on Lisp macros. I'm really  excited to figure out what other topics about macros can be applied to the seemingly unrelated field of functional components for building user interfaces on the Web.

## Links
- [Let Over Lambda](https://www.lulu.com/en/en/shop/doug-hoyte/let-over-lambda/paperback/product-18dzger.html): 50 Years of Lisp, by [Doug Hoyte](https://hoytech.com/).
- [Reagent](https://reagent-project.github.io/): A simple [ClojureScript](https://clojurescript.org/) interface to [React](https://reactjs.org/).