From 119cf7f780375187dbe3d064263a9de3a17f538d Mon Sep 17 00:00:00 2001 From: Jake Zerrer Date: Sun, 30 Nov 2025 12:31:01 -0500 Subject: Move from github pages to server --- src/pages/missionary.clj | 151 ----------------------------------------------- 1 file changed, 151 deletions(-) delete mode 100644 src/pages/missionary.clj (limited to 'src/pages/missionary.clj') 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"]]]]))) -- cgit v1.2.3