I’ve time to take a little look now, so here are some early thoughts. I don’t know concrete optics, and haven’t studied the data structures chosen yet, so this is superficial style review for now. Looking at base.clj
, do you want typo reports, like the fact that “single” is misspelled in the doc-string in line 7?
The first thing that jumped out at me is that preview
returning :nothing
if it fails is non-idiomatic, it’s much more common in such cases to simply return nil
, which is also falsey. And that would simplify the code, as well, since nil
is generally safe to do things with because of nil
-punning (my snippets for illustration here are compressed and omit the doc strings, you would stick with the way you actually wrote them):
(defn preview [optic whole]
(let [lst ((get-capability :to-list optic) whole)]
(first lst)))
That becomes so simple that you don’t even need the let
-binding. But even if there is a domain-specific reason that returning :nothing
is more useful than nil
, a more idiomatic way of writing your last expression would be:
(or (first lst) :nothing)
Since you are looking for opportunities for abstraction, there are several functions that look more or less the same, view
, to-list
, and review
for example, could all be one function, if we could come up for a good name for it (here is my lack of domain knowledge interfering). But say we called it find
, you would pass it the optic and either a whole or part, which we could perhaps call part
since a whole is a part, right? 
(defn find [optic part k]
((get-capability k optic) part))
Then the three functions I mentioned would just be calling this with values for k
of :view
, :to-list
, and :review
, respectively.
You might even be able to build this up with additional optional arguments to encompass some of the other functions which apply transformations to the result of calling get-capability
.
I would definitely caution against writing or using a function like rev-comp
. It’s non-idiomatic and very limited compared to comp
, taking only two functions and building a function that takes only one argument. comp
can take an arbitrary number of functions which each take an arbitrary number of arguments. Experienced Clojure developers are used to comp
and the order it applies functions (which is also consistent with the mathematical notation for composition of functions), so it would benefit you to get comfortable with that rather than introducing an incompatible and limited replacement.
But I should delve deeper into some of the functions you are calling here before speculating more at the top level, let’s see when I have some more time. But even before then, please let me know if this is the kind of thoughts you are looking for?