2016-03-03 29 views
0

我想1)用下面的函数创建一个符号列表;然后2)使用这些符号/名称创建原子,以便可以从其他函数修改原子。这是为了产生符号/名称的功能:用函数创建clojure原子

(defn genVars [ dist ] 
    (let [ nms (map str (range dist)) neigs (map #(apply str "neig" %) nms) ] 
     (doseq [ v neigs ] 
      (intern *ns* (symbol v) [ ])) 
    )) 

如果DIST = 3,则3个符号,neig0,... neig2被创建的每个用空载体结合。如果可以使用这些符号在功能上创建原子,以便可以从其他函数访问它们。任何帮助都非常感谢,即使有其他方法可以完成此任务。

+0

但是,你的功能的实际问题是什么?你在当前命名空间中生成符号,所以你只需要用'atom'调用来包装你的向量。 – leetwinski

回答

1

生成名称的愿望,意味着你将会通过一个单一的地图,而不是得到更好的服务:

(def neighbours (atom (make-neighbours))) 

make-neigbours的定义可能是这个样子:

(defn make-neighbours [] 
    (into {} (for [i (range 10)] 
      [(str "neig" i) {:age i}]))) 

当其他命名空间会看起来像使用类似的值:

(get-in @data/neighbours ["neig0" :age]) 

习惯性Clojure倾向于避免创建许多命名的全局变量,而宁愿将状态并置到由Clojure的并发原语(atom/ref/agent)控制的一个或几个变量中。我鼓励你想想你的问题是否可以用这种方式用单个原子来解决,而不是要求定义多个变量。尽管如此,如果您真的需要多个原子,请考虑将它们全部存储在一个地图var中,而不是创建许多全局变量。就我个人而言,我从来没有遇到过创建多个原子比单个大原子更好的情况(所以我会有兴趣知道这种情况很重要)。

如果您确实需要很多变量,请注意,在函数中定义变量实际上是不好的样式(https://github.com/bbatsov/clojure-style-guide#dont-def-vars-inside-fns)。也有很好的理由!使用功能和数据的美妙来自于功能的纯粹性。 def函数内部特别讨厌,因为它不仅是一种副作用,而且是一种潜在的执行流改变副作用。

当然是有一种方法可以实现它,正如另一个答案指出的那样。

说到定义超出defdefn的东西,使用宏有很多优先权。例如来自compojure的defroutes,来自Schema的defschema,来自clojure.test的deftest。一般来说,任何创建变量的方便形式都可以。你可以使用宏的解决方案,为您创造原子DEFS:

(defmacro defneighbours [n] 
`(do 
    [email protected](for [sym (for [i (range n)] 
       (symbol (str "neig" i)))] 
    `(def ~sym (atom {})))) 

在我看来,这是不是一个功能版本的攻势居然少,不仅因为它是创造全球DEFS。通过使用常规的def语法来创建全局视图更为明显。但我只是把它作为一个稻草人来提出来,因为这仍然很糟糕。

功能和数据效果最好的原因是因为它们组成。

有一些有形的考虑因素使得单个原子控制状态非常方便。您可以方便地遍历所有邻居,您可以动态添加新邻居。你也可以做一些事情,如连接邻居和其他邻居等。基本上有很多功能/数据抽象,如果你创建了许多全局变量,你就会锁定自己。

这就是宏一般认为对语法技巧有用的原因,但最好避免使用函数和数据。它对代码的灵活性有着实际的影响。例如回到组合;宏语法实际上是非常有限的,因此我宁愿不使用defroutes

总结:

  1. 不要让许多全球DEFS的,如果你能避免它。
  2. 在可能的情况下,优先选择多个原子上的1个原子。
  3. 不要在函数内部定义。
  4. 最好避免使用宏来支持函数和数据。
  5. 无论这些指导方针如何,探索什么是可能的,并且我无法了解您的情况总是很好的,所以我希望您最终克服了您的直接问题,并找到了一种令人愉快的语言来使用Clojure。
+2

不需要这是一个宏,它可以只是一个函数。 –

+0

优秀!谢谢您的回答。我相信要么是合适的。原子矢量是否有变化,以便我可以用名称来引用原子,就像在第一个解决方案中那样,而不是通过索引到矢量中? – Brian

+0

如果您使用地图而不是矢量,您可以按名称查找:'(def atoms(into {}(for [n names] [n(atom {})]))' –

2

你的功能似乎是正确的,只需在intern呼叫中用​​呼叫打包呼叫。另外我宁愿使用dotimes

user> 
(defn gen-atoms [amount prefix] 
    (dotimes [i amount] 
    (intern *ns* (symbol (str prefix i)) (atom [])))) 
#'user/gen-atoms 
user> (gen-atoms 2 "x") 
nil 
user> x0 
#atom[[] 0x30f1a7b] 
user> x1 
#atom[[] 0x2149efef]