Welcome! Please see the About page for a little more info on how this works.

+1 vote
in Collections by

One of the great features of Clojure is that it considers collections as functions which means that it is possible to invoke them

({:a 1, :b 2} :a) => 1
(#{:a :b} :a) => :a
([:a :b :c] 1) => :b

However it would be nice to be able to query the domain and range of those functions independently of their specific type.

The keys and vals functions currently implement this but only for Maps. I think it would be a good idea to make those functions more generic by accepting sets and vectors like in the following examples:

(keys  #{:a :b}) => (:a :b)
(vals #{:a :b}) => (:a :b)
(keys [:a :b :c]) => (0 1 2)
(vals [:a :b :c]) => (:a :b :c)

The specific use case I have in mind where this feature could be useful is to define a shorter syntax for explicit foreign key mapping in a data oriented DSL for relational data modeling, where #{:attr1 :attr2} could be used as a shortcut for {:attr1 :attr1, :attr2 :attr2}.

3 Answers

0 votes
by

I think it’s very unlikely we are going to do that in Clojure but you can add any meta you want to your vars and then drive things from that.

by
Thanks for the quick reply and your honest answer.
0 votes
by

I agree that might make sense, at least keys seems to be paired well with get, assoc and contains? both on vectors and maps.

If you want this functionality for DSL, you can implement it yourself:

(defprotocol FiniteFn
  (inputs [this] "Returns a set of all valid inputs to this fn")
  (outputs [this] "Returns a set of all valid outputs of this fn"))

(extend-protocol FiniteFn
  clojure.lang.IPersistentMap
  (inputs [m] (set (keys m)))
  (outputs [m] (set (vals m)))
  clojure.lang.IPersistentVector
  (inputs [xs] (set (range (count xs))))
  (outputs [xs] (set xs))
  clojure.lang.IPersistentSet
  (inputs [s] s)
  (outputs [s] s))

(inputs {:a 1}) => #{:a}

(inputs [:a :b]) => #{0 1}

(outputs {:a 1 :b 1}) => #{1}
by
Yes the fact that those generic domain/range functions are not implemented in the core of the language is indeed not a blocker for my use case. Thanks for providing an implementation.
0 votes
by

In case it is of someone's interest, I have just discovered that Racket is implementing a similar idea with the Dictionary interface which provides the dict-keys and dict-values on hash tables and vectors (but not on sets).

...