Sseveral comments regarding the pinholes post, have forced me, against the deepest elements of my nature, to engage in thought. Since that might never happen again, I thought it meet to record the event.
I'm going to say "I" a lot, because this is mostly my opinions.
Bidirectional programming
As pointed out by Christian Schuhegger in a comment on the original post, lenses were originally introduced to computer science in the context of bidirectional programming, rather than as a tool for dealing with deeply nested immutable structures. He points to a good list of papers on the subject on the subject. I was, it seems, excessively influenced by the use case from the Scalaz tutorial (if not by the exact details).
The original metaphor was, I suppose, that light rays traced out the
same path through a lens, irrespective of direction. My take on the
metaphor - that a lens is so called because it focuses on small or distant
things - is,
it seems to me, compelling, but it is not the original intent. Within
the context of the original definition (well not the original,
original definition, which would be anything in the shape of a
lentil), it seems like the things I create with mk-ph-set
and
mk-ph-get
are acceptably the ADT equivalent of lenses, but the
mk-ph-mod
artifacts are really state transformers. Irrespective
of name, however, a tool for dealing with deeply and weirdly
nested immutable data structures is demonstrably important to have, and I'm not
penitent or creative enough to come up with a completely different metaphor.
Fresnel and protocols and aesthetics
Someone (whose name I'll publish if he asks me to) on twitter mentioned fresnel, which is also a lens library. I did know about this before blogging, but I didn't really want to argue about the differences, because it's such a nice and polished piece of work.
Now that the subject has come up, I'll cop to being aesthetically opposed to
creating a protocol for anything that could potentially show up as (or in)
the second argument to assoc
(or assoc-in
), especially since, if
the first argument is a hash-map, Lens
becomes an incomplete proxy for
Object
.
Clojure and Clojurescript protocols pay homage to the object-oriented
nature of their virtual machines, but do so in moderation, providing
abstractions over fundamentally different implementations of
fundamental objects that are used in essentially the same way.
Hence IPersistentMap
being
implemented by both (hash-map)
and (sorted-map)
, or
core.async
having different impl
namespaces for Clojure
and Clojurescript.
In Java code reviews, the detection of
cond
-like logic immediately results in prescription for
a new interface
. Not so, in Clojure, which recognizes the limitations
of virtual function dispatch and so provides rich semantics for computed
dispatch. In Java, the interface
is the interface: instructions
for using a new library generally involve telling you to implement one.1
Clojure, I think, avoided the word "interface" in conscious rejection of this paradigm.
Pinhole relies on implementations of clojure.lang.Associative
, to do the right thing
when assoc
and get
are ultimately called, but beyond that differentiates only between keys that are
vectors and keys that are not vectors, and in the rare case where you want a vector as a hash key, you have
provide an [in,out]
function pair to do the dirty work. That feels right to me, but opinions may of course differ.
-
Though, perhaps, the wind that brought lambdas to Java 8 may carry off a few of those idioms eventually. ↩
Comments
comments powered by Disqus