Perhaps I should explain a little more about my goals, and you could decide if and how to give me guidance on the best approach.
I would like to implement the S, K, I combinators (and others) as sequential collections of arbitrary values (including nested collections). This works; I can do it with pencil and paper. Lots of paper.
In Clojure, I have composed those combinators using vectors of values. I already have a function appli
(intentionally mis-spelled so I don't mask apply
) that inspects the contents of the vector that implements the combinator, and that of any arguments, then performs the application of the combinator to the arguments. For example, the Identity combinator, I
, is a vector that contains some stuff, such that the Clojure expression
(appli I x)
evaluates to x
, corresponding to what I write with pencil on paper, like this
Ix = x
Similarly, the K combinator, K
, is a vector that contains some other stuff, such that the Clojure expression
(appli K x y)
yields K
's first argument x
, corresponding to what I write with pencil on paper
Kxy = x
And for completeness, the S combinator, S
, is a vector that contains yet different stuff, such that the Clojure expression
(appli S x y z)
yields ((x z) (y z))
, which corresponds to what we might write with pencil on paper
Sxyz = xz(yz)
It would make the ergonomics much better if I could eliminate all those instances of appli
sprinkled throughout.
To make the Clojure expressions neatly match the pencil-on-paper versions, I would like for S, K, I, etc., to:
a. When constructed, inspected, and manipulated, behave as a sequential collection of arbitrary values, supporting all the sequence functions of clojure.core;
b. When in the function position of a list, behave as a function with an implicit appli
, i.e.,
(I x) ;; => x
(K x y) ;; => x
(S x y z) ;; => ((x z) (y z))
When I originally asked my question, it seemed that a Clojure vector is almost exactly what I wanted: A vector is a sequential of arbitrary values, and may be conveniently created and manipulated by all the Clojure core sequence functions. Plus, when in the function position of a list, a vector behaves as an implicit nth
/get
function. I want the same behaviors for these combinators, except that when in the function position of a list, instead of nth
/get
behavior, the combinator should perform appli
.
Perhaps the way I presented my question gives the impression that I want to make a wonky vector. I don't actually want to make a data structure, per se, with unusual semantics. What I really want to do is make a function-like thing whose implementation is a sequence of values, which incidentally may be manipulated with the core library (not to mention a Clojure vector's efficiencies from structural sharing and performance guarantees).
But I don't want to make the combinators from everyday functions: The crucial aspect of my study is that it is the contents of the sequence that is the actual implementation of the combinator, and appli
, which is a regular everyday function, inspects the contents of the sequence and performs the desired actions.
My first instinct was to make a (hopefully) small modification to Clojure's built-in vector, but you discourage that, and anyways, I am having trouble‡ with the Java aspects. If you have a simpler/performant/cleaner/safer approach, I would certainly try that.
I don't necessarily want to re-implement from the ground up a vector that mis-behaves. I'm just trying to make the Clojure code look like my pencil-on-paper notes.
If I could do something brute force, such as copy-paste clojure/src/jvm/clojure/lang/PersistentVector.java
, rename the class, modify the invoke method, then compile, I'd be happy with an ugly solution, as long as it works. But I thought the gen-class
approach might somehow be more idiomatic, elegant, and/or correct.
(Would it be better if I submitted this different perspective as a new question?)
‡ Just to illustrate how Java-inept I am: I naively assumed that the create
method would be executed in the DangerousVector context, not in the parent class.