用函数创建clojure原子

用函数创建clojure原子,clojure,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) [ ] )) )) 如果di

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

想要生成名称,您最好使用一个地图:

(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中,而不是创建许多全局VAR。就我个人而言,我从来没有遇到过这样一种情况,即创建多个原子比创建一个大原子更好(因此,我很想听听这一点很重要的情况)

如果您确实需要很多变量,请注意在函数中定义变量实际上是一种糟糕的样式()。也有很好的理由!使用函数和数据的美妙之处在于函数的纯洁性<函数内部的code>def尤其令人讨厌,因为它不仅是一个副作用,而且是一个可能改变执行流的副作用

当然,正如另一个答案所指出的,有一种方法可以实现这一目标

在定义超出
def
defn
的内容时,使用宏有很多优先权。例如,来自compojure的
defroutes
,来自Schema的
defschema
,来自clojure.test的
deftest
。一般来说,任何创建变量的方便形式。可以使用宏解决方案为原子创建DEF:

(defmacro defneighbours [n]
`(do
  ~@(for [sym (for [i (range n)]
              (symbol (str "neig" i)))]
    `(def ~sym (atom {}))))
在我看来,这实际上比功能版本更具攻击性,只是因为它创建了全局def。使用常规的
def
语法创建全局def更为明显。但我只是把它当作救命稻草提出来,因为这仍然很糟糕

函数和数据工作得最好的原因是它们组成了

有一些具体的考虑因素使得单个原子控制状态非常方便。您可以方便地迭代所有邻居,还可以动态添加新邻居。您还可以做一些事情,比如将邻居与其他邻居连接起来等。如果您创建了许多全局变量,那么基本上有很多函数/数据抽象将您自己锁在外面

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

总之:

  • 如果可以避免的话,不要做太多的全局def
  • 尽可能选择1个原子而不是多个原子
  • 不要在函数内部定义
  • 最好避免使用宏,而使用函数和数据
  • 不管这些准则如何,探索什么是可能的总是好的,我不知道你的情况,所以最重要的是,我希望你克服眼前的问题,找到一种令人愉快的语言来使用Clojure

  • 生成名称的愿望表明,使用单一地图会更好:

    (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中,而不是创建许多全局VAR。就我个人而言,我从来没有遇到过这样一种情况,即创建多个原子比创建一个大原子更好(因此,我很想听听这一点很重要的情况)

    如果您确实需要很多变量,请注意在函数中定义变量实际上是一种糟糕的样式()。也有很好的理由!使用函数和数据的美妙之处在于函数的纯洁性<函数内部的code>def尤其令人讨厌,因为它不仅是一个副作用,而且是一个可能改变执行流的副作用

    当然,正如另一个答案所指出的,有一种方法可以实现这一目标

    在定义超出
    def
    defn
    的内容时,使用宏有很多优先权。例如,来自compojure的
    defroutes
    ,来自Schema的
    defschema
    ,来自clojure.test的
    deftest
    。一般来说,任何创建变量的方便形式。可以使用宏解决方案为原子创建DEF:

    (defmacro defneighbours [n]
    `(do
      ~@(for [sym (for [i (range n)]
                  (symbol (str "neig" i)))]
        `(def ~sym (atom {}))))
    
    在我看来,这实际上比功能版本更具攻击性,只是因为它创建了全局def。使用常规的
    def
    语法创建全局def更为明显。但我只是把它当作救命稻草提出来,因为这仍然很糟糕

    原因