用函数创建clojure原子

时间:2016-03-03 22:19:09

标签: clojure

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

(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,每个符号用空向量绑定。如果可以在功能上创建具有这些符号的原子,以便可以从其他函数访问它们。任何帮助都非常感谢,即使有其他方法可以实现这一目标。

2 个答案:

答案 0 :(得分:2)

您的功能似乎是正确的,只需使用intern来调用atom来电中的值。我也宁愿使用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]

答案 1 :(得分: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)管理的一个或几个变量。我鼓励您考虑用这种方式用单个原子解决问题,而不是要求定义多个变量。

话虽如此,如果你真的需要多个原子,可以考虑将它们全部存储在一个map 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
  ~@(for [sym (for [i (range n)]
              (symbol (str "neig" i)))]
    `(def ~sym (atom {}))))

在我看来,这实际上不如功能版本具有攻击性,只是因为它正在创建全局defs。通过使用常规def语法创建全局defs更为明显。但我只是把它当作一个稻草人,因为这仍然很糟糕。

功能和数据最有效的原因在于它们的组成。

有一些切实的考虑使得单个原子控制状态非常方便。您可以方便地遍历所有邻居,可以动态添加新邻居。你也可以做一些事情,比如将邻居与其他邻居连接起来等等。基本上,如果你创建了许多全局变量,你可以锁定很多函数/数据抽象。

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

总结:

  1. 如果可以避免,请不要进行大量的全局定义。
  2. 尽可能在多个原子上选择1个原子。
  3. 不要在函数内部进行def。
  4. 最好避免使用宏来支持功能和数据。
  5. 无论这些指导方针如何,探索可行的东西总是好的,我无法了解你的情况,所以最重要的是我希望你克服眼前的问题并找到Clojure一种令人愉快的语言。