HackerReposA FIELD GUIDE TO OPEN SOURCE
ProSponsor the shelf♧ 0
← Back to top all-time
redplanetlabs
specter
Clojure2015–2025
redplanetlabs / specter

specter

Clojure(Script)'s missing piece

30Distinct people
30Mentions
2Explicit recommenders
2.6KGitHub stars
REPOSITORY AT A GLANCE

What to know before exploring

What it is

Clojure(Script)'s missing piece

GitHub

Where it is used

No documented product use was verified in the last source check.

What people are saying

This might have been unintentional, but I suspect "Spectre of Structure" and "Python's missing piece" refer to Nathan Marz's specter library for clojure [1], similarly touted…

hessammehr used a recommendation phrase. 2 indexed comments match. This is a phrase match, not a verdict.

No classified warning is attached to this page. Read the discussions before treating silence as approval.

Also in these discussions

Mentioned in the same Hacker News threads. That is not proof they are substitutes.

This week on Hacker News

Nov 7–Nov 14 UTC · Direct repository links and separately labeled related project stories. Indexed through 11/14/2026, 3:56:07 PM UTC.

No direct repository links were found in the indexed HN discussions over the past seven days. Older discussions are available below.

Mentions over time

HN mentions by year30 dated mentions

Observed mentions: 2015-05-14 16:23:57 UTC to 2025-08-27 17:07:14 UTC.

0123452015-01-01 00:00:00 UTC to 2016-01-01 00:00:00 UTC (exclusive): 5 mentions; 2 submissions, 3 comments20152016-01-01 00:00:00 UTC to 2017-01-01 00:00:00 UTC (exclusive): 2 mentions; 0 submissions, 2 comments2017-01-01 00:00:00 UTC to 2018-01-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments2018-01-01 00:00:00 UTC to 2019-01-01 00:00:00 UTC (exclusive): 5 mentions; 0 submissions, 5 comments2019-01-01 00:00:00 UTC to 2020-01-01 00:00:00 UTC (exclusive): 3 mentions; 0 submissions, 3 comments2020-01-01 00:00:00 UTC to 2021-01-01 00:00:00 UTC (exclusive): 5 mentions; 0 submissions, 5 comments20202021-01-01 00:00:00 UTC to 2022-01-01 00:00:00 UTC (exclusive): 3 mentions; 1 submissions, 2 comments2022-01-01 00:00:00 UTC to 2023-01-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2023-01-01 00:00:00 UTC to 2024-01-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments2024-01-01 00:00:00 UTC to 2025-01-01 00:00:00 UTC (exclusive): 2 mentions; 0 submissions, 2 comments2025-01-01 00:00:00 UTC to 2026-01-01 00:00:00 UTC (exclusive): 3 mentions; 0 submissions, 3 comments2025

Counts come from the repository’s dated source evidence. Index cutoff: 2026-11-02 08:16:59 UTC.

View mention counts and date ranges
UTC ranges include their start and exclude their end. Select a period to filter the source evidence.
PeriodStart (UTC)End (exclusive, UTC)MentionsSubmissionsComments
20152015-01-01 00:00:00 UTC2016-01-01 00:00:00 UTC523
20162016-01-01 00:00:00 UTC2017-01-01 00:00:00 UTC202
20172017-01-01 00:00:00 UTC2018-01-01 00:00:00 UTC101
20182018-01-01 00:00:00 UTC2019-01-01 00:00:00 UTC505
20192019-01-01 00:00:00 UTC2020-01-01 00:00:00 UTC303
20202020-01-01 00:00:00 UTC2021-01-01 00:00:00 UTC505
20212021-01-01 00:00:00 UTC2022-01-01 00:00:00 UTC312
20222022-01-01 00:00:00 UTC2023-01-01 00:00:00 UTC000
20232023-01-01 00:00:00 UTC2024-01-01 00:00:00 UTC101
20242024-01-01 00:00:00 UTC2025-01-01 00:00:00 UTC202
20252025-01-01 00:00:00 UTC2026-01-01 00:00:00 UTC303

From the project README

An excerpt from the repository, fetched Nov 13, 2026.

Read the project’s introduction
Specter Specter rejects Clojure's restrictive approach to immutable data structure manipulation, instead exposing an elegant API to allow any sort of manipulation imaginable. Specter especially excels at querying and transforming nested and recursive data, important use cases that are very complex to handle with vanilla Clojure. Specter has an extremely simple core, just a single abstraction called "navigator". Queries and transforms are done by composing navigators into a "path" precisely targeting what you want to retrieve or change. Navigators can be composed with any other navigators, allowing sophisticated manipulations to be expressed very concisely. In addition, Specter has performance rivaling hand-optimized code (see this benchmark). Clojure's only comparable built-in operations are get-in and update-in, and the Specter equivalents are 30% and 85% faster respectively (while being just as concise). Under the hood, Specter uses advanced dynamic techniques to strip away the overhead of composition. There are some key differences between the Clojure approach to data manipulation and the Specter approach. Unlike Clojure, Specter always uses the most efficient method possible to implement an operation for a datatype (e.g. last vs. LAST). Clojure intentionally leaves out many operations, such as prepending to a vector or inserting into the middle of a sequence. Specter has navigators that cover these use cases (BEFORE-ELEM and before-index) and many more. Finally, Specter transforms always target precise parts of a data structure, leaving everything else the same. For instance, ALL targets every value within a sequence, and the resulting transform is always the same type as the input (e.g. a vector stays a vector, a sorted map stays a sorted map). Consider these examples: Example 1: Increment every even number nested within map of vector of maps (def data {:a [{:aa 1 :bb 2} {:cc 3}] :b [{:dd 4}]}) ;; Manual Clojure (defn map-vals [m afn] (->> m (map (fn [[k v]] [k (afn v)])) (into (empty m)))) (map-vals data (fn [v] (mapv (fn [m] (map-vals m (fn [v] (if (even? v) (inc v) v)))) v))) ;; Specter (transform [MAP-VALS ALL MAP-VALS even?] inc data) Example 2: Append a sequence of elements to a nested vector (def data {:a [1 2 3]}) ;; Manual Clojure (update data :a (fn [v] (into (if v v []) [4 5]))) ;; Specter (setval [:a END] [4 5] data) Example 3: Increment the last odd number in a sequence (def data [1 2 3 4 5 6 7 8]) ;; Manual Clojure (let [idx (reduce-kv (fn [res i v] (if (odd? v) i res)) nil data)] (if idx (update data idx inc) data)) ;; Specter (transform [(filterer odd?) LAST] inc data) Example 4: Map a function over a sequence without changing the type or order of the sequence ;; Manual Clojure (map inc data) ;; doesn't work, becomes a lazy sequence (into (empty data) (map inc data)) ;; doesn't work, reverses the order of lists ;; Specter (transform ALL inc data) ;; works for all Clojure datatypes with near-optimal efficiency Latest Version The latest release version of Specter is hosted on Clojars: Learn Specter Introductory blog post: Clojure's missing piece Presentation about Specter: Specter: Powerful and Simple Data Structure Manipulation Note that this presentation was given before Specter's inline compilation/caching system was developed. You no longer need to do anything special to get near-optimal performance. Screencast on Specter: Understanding Specter List of navigators with examples: This wiki page provides a more comprehensive overview than the API docs about the behavior of specific navigators and includes many examples. Core operations and defining new navigators: This wiki page provides a more comprehensive overview than the API docs of the core select/transform/etc. operations and the operations for defining new navigators. This wiki page explains how to do precise and efficient recursive navigation with Specter. This wiki page provides a comprehensive overview of how to use Specter's zipper navigators. Zippers are a much slower navigation method but can perform certain tasks that are not possible with Specter's regular navigators. Note that zippers are rarely needed. Cheat Sheet API docs Performance guide: This post provides an overview of how Specter achieves its performance. Specter's API is contained in these files: specter.cljc: This contains the built-in navigators and the definition of the core operations. transients.cljc: This contains navigators for transient collections. zipper.cljc: This integrates zipper-based navigation into Specter. Questions? You can ask questions about Specter by opening an issue on Github. You can also find help in the #specter channel on Clojurians. Examples Increment all the values in maps of maps: user> (use 'com.rpl.specter) user> (transform [MAP-VALS MAP-VALS] inc {:a {:aa 1} :b {:ba -1 :bb 2}}) {:a {:aa 2}, :b {:ba 0, :bb 3}} Increment all the even values for :a keys in a sequence of maps: user> (transform [ALL :a even?] inc [{:a 1} {:a 2} {:a 4} {:a 3}]) [{:a 1} {:a 3} {:a 5} {:a 3}] Retrieve every number divisible by 3 out of a sequence of sequences: user> (select [ALL ALL #(= 0 (mod % 3))] [[1 2 3 4] [] [5 3 2 18] [2 4 6] [12]]) [3 3 18 6 12] Increment the last odd number in a sequence: user> (transform [(filterer odd?) LAST] inc [2 1 3 6 9 4 8]) [2 1 3 6 10 4 8] Remove nils from a nested sequence: user> (setval [:a ALL nil?] NONE {:a [1 2 nil 3 nil]}) {:a [1 2 3]} Remove key/value pair from nested map: user> (setval [:a :b :c] NONE {:a {:b {:c 1}}}) {:a {:b {}}} Remove key/value pair from nested map, removing maps that become empty along the way: user> (setval [:a (compact :b :c)] NONE {:a {:b {:c 1}}}) {} Increment all the odd numbers between indices 1 (inclusive) and 4 (exclusive): user> (transform [(srange 1 4) ALL odd?] inc [0 1 2
Read the full README on GitHub

What Hacker News says

30 sources
The three things I have repeatedly failed to learn, they just don't seem to stick for me: Dvorak, Specter[1] (the Clojure library), and APL. So I appreciate these tips whenever I find them. My issue with APL is I was never able to turn the corner to "generic problem solving" in APL (or other array langs). It feels like learning written Chinese, like 50,000 individual techniques but if you know them you can do incredible things quickly. For the problems I know how to solve, I can solve them quickly. And you CAN do amazing things with inner products in APL. On the other hand, studying APL, even if you don't master it, is not without benefits. LLM transformer architecture and GraphBLAS algorithms are junior APL level implementation problems (at least conceptually, operationalizing them is a different story). Adam Brudzewski has one of the
Read the rest
most criminally underrated YouTube channels[2]. It would be great to solve problems that elegantly in any language, and Adam has always been very friendly in answering questions if you ever get a chance to speak with him. I just seem to be a lost cause lol. [1]: https://github.com/redplanetlabs/specter [2]: https://www.youtube.com/@abrudz
In Efficient Array Programming
> There is no way to know what's being passed around without reading the source of the whole chain. But that's not what a Clojure dev would do. 1) We use Malli [0] (or similar) to check specs and coerce types if needed at every point. Checks can be left on in production (I do), or disable–up to you. 2) If the coercion is difficult, use something like Meander. [1] 3) If even that isn't straightforward and you need actual logic in the loop, use Specter. [2] 4) If you're not sure what going on at intermediate steps, use FlowStorm [3]. 5) But you're going to be processing a lot of data you haven't seen before! Use, Malli with test.check [4] and make use of property-based testing with generators. None of this is "advanced" Clojure, this is bread-and-butter stuff I use every day. 6) Need a Notebook-like experience to get better visualization of
Read the rest
intermediate data? Use Clerk [5]. 7) Need special checks on API usage within your codebase? Use clj-kondo [6] with custom linters. They're less than 10 lines each. Unlike default-mutable languages, or typed, it's safe and easy to use libraries with Clojure and they tend to have very little churn. Total opposite from Python or JavaScript (if you're used to that). It's almost impossible to give the impression of what it is like to develop with Clojure if you've only ever used languages with static typing, or languages from the Algol family. Honestly, I hated Clojure's syntax at first BECAUSE I COULDN'T READ IT, and I loathed "structural editing." After 2-3 weeks, I read it just fine and it's hard to remember I ever couldn't do so. Now I like it, and structural editing makes it so easy to change your code, I couldn't live without it at this point. Basically, all my "fears"/dislikes were unfounded—it was a skill issue on my part, not a problem with Clojure. [0] https://github.com/metosin/malli [1] https://github.com/noprompt/meander [2] https://github.com/redplanetlabs/specter [3] https://www.flow-storm.org/ [4] https://github.com/clojure/test.check [5] https://clerk.vision/ [6] https://github.com/clj-kondo/clj-kondo
In Why Clojure?
> You might just be using a completely different underlying data structure than expected, depending on which operations you've performed. I haven't had the pleasure of using Clojure in production, but I'm somewhat obsessed with the language and follow it fairly closely. Someone on r/Clojure[1] mentioned Specter[2] with a link to this video[3]. One of the first things the video covers is how the library deals with this concern. [1] https://www.reddit.com/r/Clojure/comments/loz77v/just_came_a... [2] https://github.com/redplanetlabs/specter [3] https://www.youtube.com/watch?v=rh5J4vacG98
In Clojure from a Schemer's Perspective
I'm still salty about Specter[0] not being ~officially recognised as a necessity when using Clojure. [0] https://github.com/redplanetlabs/specter Data driven languages need simple & powerful transformation libraries. `get-in` is repetitive and tiresome to use. Specter and it's ilk make transformations clear and simple. No amount of planning or foresight negates the need for data transformation libraries.
In The Future of Clojure
I think rewrite is related to program transformation [1]? Most stuff that I've seen looks pretty academic, obscure, not very well maintained, etc ... Pure [2] is the only practical language I've stumbled upon that appears to be general purpose _and_ based on term rewrite. I wonder if XSLT could fall under this umbrella? It rewrites trees into other trees ... not sure if that's enough to be considered a term rewrite system. If yes, then maybe CDuce is also an interesting thing to check. The author of Ragel also has a program transformation system [4], but I'm not sure what state it is at, he seems to have been working on it for a long while but it doesn't seem to be something nearly as popular as Ragel. Edit: I think specter [5] and meander [6] also could be, perhaps tangentially, related to rewriting. Meander expressly mentions rewrite as
Read the rest
In Exotic Programming Ideas, Part 2: Term Rewriting
Specter is tremendously useful and rarely lets on a case where it can’t perform a transformation. For ensuring that you’re getting the most efficient form of a transformation [0] it’s incredible —- and it is somewhat data-oriented, allowing easy saving and reuse of navigators. Meander [1] is also wonderful. Its unification-based approach makes for nice expressions of intent. Its strategy-based approach to rewriting [2] is more flexible than most common walker libraries, too. [0]: https://github.com/redplanetlabs/specter/wiki/Specter's-inli... [1]: https://github.com/noprompt/meander [2]: https://github.com/noprompt/meander/blob/epsilon/doc/strateg...
In Specter – Clojure API for immutable programming (2017)
This sounds fishy to me too... Have you actually consulted anyone, with more Clojure experience, how to avoid the need for `(map vec <thing>)` all over the place? I would guess you were working with deeply nested data structures and you had to do deep updates, while strictly maintaining the vector data-type. That's indeed kinda sucky to do just using vanilla `clojure.core`, indeed, but then there is https://github.com/redplanetlabs/specter for that. Alternatively, instead of dealing with deep nesting, you should probably work with namespaced keys, which allow flattening your data and suddenly a lot of transformations become radically simpler and such a system is more extensible too...
In A History of Clojure [pdf]

Showing the 15 most recent of 30 sources. Enable JavaScript to search and browse every indexed mention.

MAKE YOURSELF AT HOME

A few shortcuts

/
Search the collection
?
Open this guide
Esc
Close dialogs and navigation

Your saved repositories and interests stay in this browser.