2024 Clojure调查问卷中分享您的想法!

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

+1 投票
Collections

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 投票

我同意这可能是合理的,至少 keysgetassoccontains? 在向量和映射中都很好地配对。

如果您想在 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(但在集合上不提供)。

...