所以我在这里有这段代码,它会生成如下数组:
(gen_array 10 3) -> [10 10 10] (puts 3 10's into array)
(gen_array "Hello" 3) -> ["Hello" "Hello" "Hello"]
但它不起作用,并在ArityException
上返回thread "main"
。
这是一个更详细的错误:
Exception in thread "main" clojure.lang.ArityException: Wrong number of args (2) passed to: PersistentVector
以下是代码:
(ns test.core
(:gen-class))
(defn gen_array [n times]
((def out []) (for [x (range times)] (conj out n)) out))
(defn -main []
(println (gen_array 10 3)))
答案 0 :(得分:1)
你的代码有一些概念性的语义和风格误解:
首先,实际错误是由于您尝试将(def out [])
作为函数返回的内容调用而引起的。因为它返回一个向量,所以将它作为函数调用是完全可以的,如果你将索引作为参数传递给它,但是在这里传递两个参数,即(for [x (range times)] (conj out n))
和out
,所以它结束了有一个arity例外。
第二:即使你将它重写为
(defn gen_array [n times]
(def out [])
(for ...))
或(这是引入绑定的正确方法)
(defn gen_array [n times]
(let [out []]
(for [x (range times)] (conj out n))
out))
它仍然无法添加到out
,因为clojure的数据是不可变的,for
是懒惰的,所以你总是会得到空列表:< / p>
user> (gen_array :x 10)
;; []
使用for
完成此任务的正确方法是:
user> (defn gen-array [n times]
(vec (for [_ (range times)] n)))
;; #'user/gen-array
user> (gen-array :x 10)
;; [:x :x :x :x :x :x :x :x :x :x]
但最简单的是:
user> (defn gen-array [n times]
(vec (repeat times n)))
;; #'user/gen-array
user> (gen-array :x 10)
;; [:x :x :x :x :x :x :x :x :x :x]
答案 1 :(得分:0)
Leetwinski已经回答得很好,但我想补充一些东西,并以不同的方式解释问题。
我认为你错过了这一点,因为你用Java或类似的语言进行编程。
第一个错误:初始集合的定义
在Clojure中,def
创建一个全局变量(在命名空间的上下文中),它也存在于函数之外。
但是在这里,你定义的累加器只需要存在于函数内部,就像在类方法中一样(命名空间是一个类,函数是编译后它的子类)。
为此目的,正确的方法是使用let
,然后您的对象out
仅存在于let
的上下文中:
(let [a 2]
...do a lot of thing with your local a...
) ;; after that, you cannot call a anymore
第二个错误:out不可变
Clojure标准对象不可变,i.e.
使用f作为函数执行(f值)时,会隐式创建新对象,并且值本身不会更改:
(def value 2)
(inc value)
value ;; 2
所以即使你这样做了:
(defn gen_array [n times]
(let [out []]
(for [x (range times)] (conj out n))))
(gen_array 2 2)
您将返回([2] [2])
第三个错误:您认为for和Java一样
因为Clojure用于通过迭代输入集合来创建集合,如最后一个示例所示。实际上,当您将for
与单个集合一起使用时,它等同于map
。
在这里,你当然可以使用for
但是你最初考虑的是(在向量中积累值)是通过使用更接近Java的reduce
或loop/recur
来实现的。循环比for
和map
迭代现有集合来转换值(它就像迭代器一样)。可以使用doseq
和dotimes
。
各种解决方案
我将重写上面给出的解决方案(当然repeat
是最好的)但是这里有一些解决方案可以向您展示如何实现您的想法(Java风格):
;; Note that many of these pieces of code are not idiomatic, just for fun
;; Reduce implementation
(defn gen_array [n times]
(reduce
(fn [agg n]
(conj agg n))
[] (range times))) ;; out is []
;; Uses transitory transient collection
(defn gen_array [n times]
(persitent!
(reduce
(fn [agg n]
(conj! agg n))
(transient []) (range times))))
;; Uses an atom, which is mutable
(defn gen_array [n times]
(let [agg (atom [])
_ (dotimes [_ times] (swap! agg conj n))]
@agg))
;; Loop/recur version
(defn gen_array [n times]
(loop [out []
i 0]
(if (= times i)
out
(recur (conj out n) (inc i)))))
;; Real Java Object[] assuming you want to pass any Object !
(defn gen_array [n times]
(let [out (object-array n)]
(amap out idx ret n)))