You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何clojure.set/union函数允许非集合类型数据作为输入?

Understanding clojure.set/union Behavior with Sequences

Great question! This is such a common gotcha when you're first exploring Clojure's set utilities—let's unpack what's happening here.

Why No Type Error?

Clojure leans heavily into duck typing: instead of enforcing strict type checks upfront, it cares whether an object supports the operations it needs (like count or conj in this case). The clojure.set/union documentation states it expects input sets, but the implementation doesn't explicitly validate that you're passing sets. Since lists support both count and conj, the function just proceeds with whatever you give it.

Why That Specific Output?

Let's look at how clojure.set/union works under the hood for two arguments:

([s1 s2]
  (if (< (count s1) (count s2))
    (reduce conj s2 s1)
    (reduce conj s1 s2)))

In your example, you're passing two lists: '(1 2 3) and '(2 3 4). Both have a count of 3, so it runs (reduce conj '(1 2 3) '(2 3 4)).

Here's the step-by-step breakdown:

  • reduce uses the conj function, starting with the initial list '(1 2 3), and processes each element from the second list:
    1. conj '(1 2 3) 2 → (2 1 2 3) (since conj adds elements to the front of a list)
    2. conj (2 1 2 3) 3 → (3 2 1 2 3)
    3. conj (3 2 1 2 3) 4 → (4 3 2 1 2 3)

That's exactly the output you saw! Since you're using lists instead of sets, conj doesn't handle deduplication—sets automatically ignore duplicate elements when you conj them, but lists don't.

The Correct Usage (For Union Semantics)

To get the actual set union behavior you expect, make sure to pass sets instead of lists:

user=> (clojure.set/union #{1 2 3} #{2 3 4})
#{1 2 3 4}

If you're working with sequences and want to treat them as sets, convert them first:

user=> (clojure.set/union (set '(1 2 3)) (set '(2 3 4)))
#{1 2 3 4}

Enforcing Input Types (Optional)

If you want to avoid this kind of surprise in your code, add explicit checks to ensure inputs are sets. For example:

(defn safe-union [& colls]
  (assert (every? set? colls) "All inputs must be sets")
  (apply clojure.set/union colls))

Now calling (safe-union '(1 2 3) '(2 3 4)) will throw an assertion error, matching your initial expectation of a type warning.

内容的提问来源于stack exchange,提问作者Old Panda

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:54:57