summaryrefslogtreecommitdiff
path: root/src/pages/missionary.clj
diff options
context:
space:
mode:
authorJake Zerrer <him@jakezerrer.com>2025-11-30 12:31:01 -0500
committerJake Zerrer <him@jakezerrer.com>2025-11-30 17:27:46 -0500
commit119cf7f780375187dbe3d064263a9de3a17f538d (patch)
tree376d48fc42d19ed49ca3f740e7c0e4c15596d11d /src/pages/missionary.clj
parent034e30d70aeac7ce18f34be6a1c211730e9fd7fb (diff)
Move from github pages to server
Diffstat (limited to 'src/pages/missionary.clj')
-rw-r--r--src/pages/missionary.clj151
1 files changed, 0 insertions, 151 deletions
diff --git a/src/pages/missionary.clj b/src/pages/missionary.clj
deleted file mode 100644
index 2bb06de..0000000
--- a/src/pages/missionary.clj
+++ /dev/null
@@ -1,151 +0,0 @@
-(ns pages.missionary
- (:require [components :refer [page]]
- [borkdude.html :refer [html]]
- [highlight :refer [highlight-clj]]))
-
-(defn missionary []
- (page
- (html
- [:<>
- [:h1 "FRP in Clojure with Missionary"]
- [:h3 "August 2025"]
- [:p "I've been working in Clojure on and off for nearly a decade now. In
-that time, I've spent thousands of hours working in other languages
-professionally: Python, Ruby, TypeScript / Flow / JavaScript, Kotlin, and Java.
-I've experimented with many more, to varying degrees: Zig, Janet, Prolog, and
-Factor, to name a few. At the end of the day, though, I always find myself
-coming back to Clojure."]
- [:p "Though it's hard to pin down exactly why I find myself so drawn by
-the language, it seems to have something to do with the relatively high incidence
-of exposure to new, mind-expanding ideas that I've experienced while working
-in Clojure and its ecosystem."]
- [:p "For one reason or another, Clojure seems to attract a high density of
-smart people who are experimenting with fairly radical ways of solving hard
-problems. Something about the combination of the language's simple macro system,
-data orientation, reasonable performance, and practical approach to
-functional programming make it a great foundation for building more complicated
-experimental language constructs."]
- [:p "It is via Clojure that I first came to be exposed to datalog, for example,
-which helped me begin to be able to articulate why I struggled with SQL's
-relativel lack of expressivity. From there, I discovered prolog and the world of
-\"search programming\", which gave me an entirely different way to frame
-certain problems."]
- [:p "Similarly, I first learned of Datomic through Clojure, which blew my
-mind the first time I encountered it. The idea of treating your entire database
-as a single, immutable value would never have occurred to me on my own;
-once I encountered it, however, the alternative seemed patently absurd."]
- [:p "The Clojure library " [:span.inline-code "meander"] " showed me that term rewriting systems
-could be used for data transformation. (Did you know that term rewriting systems
-have the full power of turing machines?) The folks over at Hyperfiddle
-have proven that you can effectively abstract away the network connection that
-sits between a client and a server, and they have credited Clojure for that
-accomplishment. Similarly, my experience so far with Rama, from Red Planet Labs,
-have made it hard for me to go back to \"traditional backend programming\".
-(I could write a whole series of posts on that topic. Reach out if you'd find
-that interesting.) They, too, credit Clojure for their progress."]
- [:p "In this post, I want to use the FRP library " [:span.inline-code "missionary"] " to give an
-example of what it means to embed an entirely new concept within an existing
-programming language. On the one hand, missionary is simply a library. On the
-other hand, it differs significantly from the kind of library that you might
-find in other programming languages because it introduces its own syntax and
-semantics that integrate seamlessly with the host language, Clojure. (This is
-the old \"promise of the DSL\" that lisps are famous for.)"]
- [:p "First, though: what is missionary? At a high level, missionary
-seeks to make it easier to write correct asynchronous (and concurrent) programs
-correctly, efficently (meaning that it makes effective use of available CPU
-resources), and in a manner that will feel comfortable to functional programmers.
-To accomplish that, missionary draws inspiration from a number of interesting
-programming ideas and diciplines:"]
- [:ul
- [:li "Functional Reactive Programming, or FRP"]
- [:li "Process supervision"]
- [:li "Structured concurrency"]
- [:li "Ambiguous programming"]
- [:li "TKTK"]]
- [:p "To start our journey, I want to show you the equivelant of a \"hello, world!\"
-program, written with missionary. This program captures the current time, in milliseconds;
-it sleeps for one second; and then it captures the current time again."]
- (highlight-clj
- (require '[missionary.core :as m])
-
- (def run
- (m/ap (tap> [:a (System/currentTimeMillis)])
- (m/? (m/sleep 1000))
- (tap> [:b (System/currentTimeMillis)])))
-
- (m/? (m/reduce {} nil run)))
- [:p "(In these examples, you'll note my use of the " [:span.inline-code "(tap> ...)"] " function. This
-function appends the value of its argument to a list. After the program runs,
-I print the contents of that list to the \"tap contents:\" box below the code.)"]
-
- [:p "TKTK Note, however, that " [:span.inline-code "run"] " doesn't actually execute until we feed it
-to the " [:span.inline-code "reduce"] " function. It's too early to explain how " [:span.inline-code "reduce"] " has anything
-to do with running a program – we'll have to build some other intuition first.
-For now, when you see " [:span.inline-code "reduce"] ", just think \"run a sequence of operations.\""]
-
- [:p "You might be thinking: "
- [:em "I could write this code just as easily without missionary.
-What's the point? "]
- "Great question. We should go ahead and do that. Let's write this program once
-without missionary, and then again with missionary but with a bit of additional
-debugging thrown in:"]
-
- (highlight-clj
- (defn log
- "Emit `v` to `tap>`, capturing the current time and active thread along the way."
- [v]
- (tap> [v (System/currentTimeMillis) (.getName (Thread/currentThread))]))
- (defn run-native []
- (log :native-a)
- (Thread/sleep 1000)
- (log :native-b))
-
- (tap> (-> (run-native)
- (time)
- (with-out-str)))
-
- (def run-missionary
- (m/ap (log :missionary-a)
- (m/? (m/sleep 1000))
- (log :missionary-b)))
-
- (tap> (-> (m/reduce {} nil run-missionary)
- (m/?)
- (time)
- (with-out-str))))
- ;; TODO: Fix bug where second log doesn't
- ;; always print!
-
- [:p "A few things might jump out immediately."]
- [:p "First, both "
- [:span.inline-code "run-native"] " and "
- [:span.inline-code "run-missionary"]
- " block during their evaluation. Notice that the runtime
- for each is approximately 1000ms."]
- [:p "Second, "
- [:span.inline-code "run-native"]
- " evaluates the entire expression on the repl's main thread.i By contrast, "
- [:span.inline-code "run-missionary"]
- " seems to move the
- form after the sleep expression to some kind of background thread. What's
- that about?"] [:p "Oh, by the way. At the beginning of this post, I made
- it clear that Clojure has had a major impact on the way I think about
- programming, in large part because the language has facilities that make it
- particularly attractive for experimentation. While I believe that to be
- true, I know that Clojure is hardly alone in its expressiveness. If you are
- a Haskeller, an OCameler, a Common Lisper, an APLer, or even a C
- programmer, and you're thinking to yourself \"Clojure isn't special in this
- regard\", well, I'm sure you're right! Shoot me an email with your
- thoughts, I'd love to learn more about why your language of choice is
- unique in this regard. I'll update this post with your contribution."]
- [:h2 "References"]
- [:ul
- [:li "TODO flow spec"]
- [:li "TODO task spec"]
- [:li "TODO process supervision"]
- [:li
- [:a {:href "https://github.com/leonoel/missionary"} "Missionary"]]
- [:li [:a {:href "https://github.com/hyperfiddle/electric"} "Electric Clojure"]]
- [:li [:a {:href "https://github.com/noprompt/meander"} "Meander"]]
- [:li [:a {:href "https://jimmyhmiller.com/meander-rewriting"}
- "Introduction to Term Rewriting with Meander"]]]])))