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

欢迎!请参阅关于页面了解该功能的更多信息。

+1
集合

Clojure 的一个伟大特性是它将集合视为函数,这意味着我们可以调用它们

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

但是,如果我们能够独立于其特定类型查询这些函数的 定义域值域,那就更好了。

当前的 keysvals 函数已实现这一功能,但仅限于 Maps。我认为将这些函数做成更通用的形式,接受集合和向量,是个不错的主意,如下例所示

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

...