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
: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)]
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,
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
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
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?