2013-03-01 32 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庫。