2013-03-01 52 views
3

我试图实现一个神经网络,并且每个神经元需要对其他神经元的引用。我一直试图通过原子实现这个参考。Clojure有变量引用吗?

考虑代码

(def neuron1 {:connections [(atom 0)]) 
(def neuron2 {:connections [(atom neuron1)]}) 

(update-in neuron1 [:connections 0] #(reset! % neuron2)) 

这最后会吹堆栈。

因此,它似乎是一个原子包含它的内容,而不是仅仅引用他们。

如果我想传递相当于指针的指令,该怎么办?我必须在

(def neuron1 {:connections [(fn [] neuron2)]}) 

使用功能,因为并调用它,而不是使用原子和非关联呢?

回答

5

你的代码没问题。你吹起堆栈的原因是你正在REPL上运行update-in命令,导致它打印结果。由于每个神经元嵌套在另一个神经元内,因此print语句会遇到堆栈溢出。尝试在另一个语句(例如(type))中包装update-in命令,或者在另一个函数中运行它。

3

WolfeFan已经回答了“为什么stackoverflow”的部分问题。 就指针/引用类型的特征而言,您可以将var(它绑定到神经元)存储在原子中,而不是神经元对象本身。另外,我建议将连接作为向量的原子而不是单独的连接作为原子,因为很可能您将从多个线程修改连接对象。

例子:

(def neuron1 {:connections (atom [])}) 
(def neuron2 {:connections (atom [#'neuron1])}) 

(update-in neuron1 [:connections] #(swap! % conj #'neuron2)) 

当你需要获取你需要使用var-get连接的神经元:

(-> neuron1 :connections deref (get 0) var-get) 

瓦尔本身是线程安全的,改变根,你需要一个变种的结合使用alter-var-root这是一个原子操作。

3

如果你想使用简单的Clojure数据结构,最好忘记细粒度的原子使用。取而代之的是,使一个巨大的地图来表示整个网络,也许像:

(def ann {1 {:connections [1 2 3] :weights [0.1 -0.3 0.5] :state 0.3} 2 {:connections [1 2 3] :weights [0.1 -0.3 0.5] :state 0.13} 3 {:connections [2 3] :weights [0.5 0.2] :state 0.31}}) 

然后在它降低,使用update-在等更新的节点。使所有更新函数采用不可变的数据结构,因为这将使测试更容易。

现在肯定有更好的方法来做到这一点。你最好看看@mikera一直在用矩阵做什么。或者,如果你想异步,你可以使用Lamina或新的Plumbing/Graph库。