2024 Clojure状态调查!中分享您的想法。

欢迎!请参阅关于页面以了解更多关于该如何操作的信息。

+1
集合

Clojure的一大特点是将集合视为函数,这意味着可以对其调用。

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

但是,能够在不依赖于函数特定类型的情况下独立查询这些函数的定义域和值域会更好。

当前的keysvals函数实现了这一点,但仅适用于Map。我认为使这些函数更通用,接受集合和向量等是一个好主意,如下面的示例所示。

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

我想具体用到的用例之一是,在面向数据的数据驱动的DSL(数据建模)中定义显式外键映射的简短语法,其中#{:attr1 :attr2}可用于表示{:attr1 :attr1, :attr2 :attr2}

3 答案

0

我认为在Clojure中实现这一点可能性很小,但您可以为您的变量添加任何元数据,然后从该数据驱动事件。

感谢您的快速回复和真诚的回答。
0

我同意这可能是合理的,至少`keys`看起来与`get`、`assoc`和`contains?`都很好地匹配,在向量和映射中都是如此。

如果您希望在DSL中实现此功能,您可以自行实现。

(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}
确实,这些通用的域/范围函数没有在语言的核心中实现,这确实不是我的用例的障碍。感谢您提供了实现。
0

如有需要,我刚发现Racket正通过字典接口实现了一个类似的想法,该接口在哈希表和向量上提供了`dict-keys`和`dict-values`(但在集合上没有)。

...