You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

将Scheme的flatten函数转换为Clojure时遭遇IllegalArgumentException错误的技术求助

Fixing IllegalArgumentException in Clojure Flatten Function Ported from Scheme

I ran into an IllegalArgumentException when trying to port a Scheme flatten function to Clojure, and I'm looking for help fixing it. Here's the full context:

Broken Clojure Implementation & Test Call

(defn flatten [x] 
  (cond 
    (empty? x) '() 
    (not (coll? x)) (list x) 
    :else (conj (flatten (first x)) (flatten (rest x)))
))
(flatten '((1) 2 ((3 4) 5) ((())) (((6))) 7 8 ()))

Working Scheme Version, Test Call & Output

(define (flatten x) 
  (cond 
    ((null? x) '()) 
    ((not (pair? x)) (list x)) 
    (else (append (flatten (car x)) (flatten (cdr x))))
))
(flatten '((1) 2 ((3 4) 5) ((())) (((6))) 7 8 ()))
; Output: (1 2 3 4 5 6 7 8)

What's Causing the Error?

There are two critical issues with the Clojure code that trigger the IllegalArgumentException:

  1. Misusing conj instead of concat:
    Scheme's append takes two lists and concatenates them into one. But Clojure's conj is designed to add individual elements to a collection (for lists, it adds elements to the front). When you pass (flatten (rest x)) — a full list — as the second argument to conj, it throws an error because conj doesn't accept lists as elements for this operation.

  2. Incorrect condition order:
    The first check (empty? x) will fail with an error when x is a non-collection value (like the number 2). empty? only works on collection types in Clojure, whereas Scheme's null? safely ignores non-pair values and moves to the next condition.

Fixed Clojure Implementation

Adjust the condition order to handle non-collections first, and replace conj with concat (Clojure's equivalent of Scheme's append for sequence concatenation):

(defn flatten [x]
  (cond
    (not (coll? x)) (list x)  ; Handle non-collection values first to avoid errors
    (empty? x) '()            ; Then check for empty collections
    :else (concat (flatten (first x)) (flatten (rest x)))))

; Test the fixed function:
(flatten '((1) 2 ((3 4) 5) ((())) (((6))) 7 8 ()))
; Returns: (1 2 3 4 5 6 7 8)

Extra Notes

  • coll? vs pair?: Clojure's coll? includes all collection types (lists, vectors, maps, sets), while Scheme's pair? only refers to cons pairs (list elements). If you only need to handle lists, coll? works fine; if you want to restrict to sequential collections, use sequential? instead.
  • Built-in flatten: Keep in mind Clojure already has a built-in clojure.core/flatten function, but implementing it yourself is a great way to learn about sequence manipulation!

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

火山引擎 最新活动