请分享您的想法,参与2024 Clojure状态调查!

欢迎!请参阅关于页面以获取更多关于如何工作的信息。

+1
集合

Clojure的一个显著特性是它将集合视为函数,这意味着可以将其调用

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

然而,最好能够独立于函数的具体类型查询这些函数的**定义域**和**值域**。

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

(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似乎很好地与getassoccontains?配对,这两者都用于向量和映射。

如果您想为 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 正在通过 Dictionary 接口实现类似的想法,该接口为哈希表和向量提供 dict-keysdict-values,但不适用于集合。

...