Reputation: 50077
I'm playing with a matrix implementation in Clojure which I'm doing for the fun of doing it and learning more about Clojure, rather than because I want to create the bestest fastest most coolest matrix implementation in the world.
One of the primary operations needed in code like this is the ability to return the value at a given row and column in a matrix, which of course I've written as a function
(mat-getrc m 2 3)
says "Give me the value at row 2, column 3 in matrix m". Perfectly good Clojure, but verbose and ugly. I'd rather write
(m 2 3)
but of course A) vectors (in my package matrices are just vectors) only respond to a single argument, and B) vectors don't know how to use the row and column number to figure out where the correct value is stored.
From looking at the docs for IFn
(which vectors are supposed to implement) it appears that a two-argument version of invoke
exists - but how do I get my "matrix" vectors to implement and respond to it?
Any suggestions and pointing-in-the-right-direction appreciated.
Upvotes: 3
Views: 137
Reputation: 70239
You can't modify how vectors are invoked as that's built into the implementation of vector, but you can define your own type that wraps a vector, acts as a vector, and is invokable however you like with deftype
. You would need to extend many of the same interfaces that vectors implement (this is however a large list):
user=> (ancestors clojure.lang.PersistentVector)
#{clojure.lang.IEditableCollection clojure.lang.ILookup
java.util.concurrent.Callable java.lang.Runnable clojure.lang.IMeta
java.lang.Comparable clojure.lang.IReduceInit
clojure.lang.IPersistentCollection clojure.lang.IHashEq java.lang.Iterable
clojure.lang.IReduce java.util.List clojure.lang.AFn clojure.lang.Indexed
clojure.lang.Sequential clojure.lang.IPersistentStack java.io.Serializable
clojure.lang.Reversible clojure.lang.Counted java.util.Collection
java.util.RandomAccess java.lang.Object clojure.lang.Seqable
clojure.lang.Associative clojure.lang.APersistentVector
clojure.lang.IKVReduce clojure.lang.IPersistentVector clojure.lang.IObj
clojure.lang.IFn}
Upvotes: 2
Reputation: 6509
(def matrix [[1 2 3 4][5 6 7 8][9 10 11 12]])
As you say in your question this is possible:
(matrix 2)
But this is not:
(matrix 2 3)
This would be a standard way to get the index of an index:
(get-in matrix [2 3])
You can already nearly get what you want, just with a few more parens:
((matrix 2) 3)
You could define a higher order function:
(defn matrix-hof [matrix]
(fn [x y]
(get-in matrix [x y])))
Then put the function rather than the matrix in function position:
(let [m (matrix-hof matrix)]
(m 2 3))
I don't believe that exactly what you are asking is possible using either a function or a macro.
Upvotes: 2