深入瞭解lisp(clojure)-變數

來源:互聯網
上載者:User

本文由larrylgq編寫,轉載請註明出處:http://blog.csdn.net/larrylgq/article/details/7395261

作者:呂桂強

郵箱:larry.lv.word@gmail.com

clojure中變數可以分為詞法變數(lexical)和動態變數(dynamic),有點類似於其它語言中的局部變數和全域變數。

一個變數是一個不需要聲明檔案類型的可以儲存值的具名位置。它可以儲存任何類型的值,並且這些值帶有用於運行期檢查的類型資訊。並且如果類型出錯會被動態檢測到

eg:(將一個非數字對象傳給了+函數)

從這方面來看lisp是一個強型別的且動態類型的語言。

lisp是傳值的,但是傳遞的值是對象的引用。這點和java,python類似。意味著如果一個變數修改了它指向的一個可變對象,這個改動會被應用到任何引用該對象的變數。

 

一種引入新變數的方式是通過函數形參:形參列表定義了在函數被調用的時候儲存實參的變數。

eg:(defn foo [x y z] (+ x y z))

每次函數調用的時候clojure會建立新的綁定儲存有調用者傳遞來的實參,該綁定的生命週期一直到運行期結束。(遞迴函式的形參會在每一次函數調用的時候重新綁定)

 

另一種引入新變數的方式是使用let特殊操作符。

eg:(let [variable*] body-form*)

variable可以賦初值也可以不賦,下面是一個let將x,y,z分別綁定到1,2,nil上:

(let [[x 1] [y 2] z]

...)

 let函數是一個調用匿名函數的宏,上面的例子可以展開為((fn [x y z] (...)) 1 2 nil)

let在調用結束後,如果該變數在let之前有引用,則會重新指向所引用的對象。
函數定義和let這兩種形式我們稱之為綁定形式,多個嵌套對同名變數的綁定,內層的變數綁定會覆蓋外層的。

clojure的閉包

如果一個匿名函數引用一個封閉範圍的變數就像這樣:

(let [count 0] #(fn [] (inc count)))

根據範圍規則lambda運算式中對count的引用是合法的,而且這個引用了count的匿名函數會被當作傳回值被let函數返回。

如果我們將這個運算式所建立的閉包賦值給一個全域變數例如:

(def *fn* (let [count 0] #(fn [] (inc count))))

這樣我們就可以在外部調用它

USER>(*fn*)

1

USER>(*fn*)

2

當然除此之外多個閉包也可以引用相同的變數

例如:

(let [count 0]

 (list

  #(fn [] (inc count))

  #(fn [] (deccount))

  #(fn [] count)

 )

)

 

動態變數

Clojure裡面有4種動態變數類型:Vars,Refs,Atoms 和Agents.

下面這個表格是它們之間的比較:

 這個表格裡面提到的函數我們會在後面介紹。

  Var Ref Atom Agent
目的 同步對一個本地線程的變數的修改 同步對於一個或者多個動態變數修改 同步對於一個變數進行修改 對一個變數進行非同步修改
建立方法 (def name initial-value) (ref initial-value) (atom initial-value) (agent initial-value)
修改方法 (def name new-value)
給變數賦一個新值

(alter-var-root
(var name) update-fn args)

使用var和fn動態修改一個函數的引用

(set! name new-value) 用在binding內部,修改一個執行緒區域的值

(ref-set ref new-value)
給變數賦予一個新值,必須在dosync裡面調用

(alter ref
update-fn arguments
)

修改ref的值,必須在dosync裡面調用,如果事務開始之後值改變了,那麼當前事務會進行重試

(commute ref
update-fn arguments
)

修改ref的值,必須在dosync 裡面調用,即使事務開始之後值改變了,當前事務不會進行重試

(reset! atom new-value)

不管舊的值是什麼樣子,都會儲存新值

(compare-and-set! atom current-value new-value)設定新值之前檢查舊值如果和current-value相同才會設定並返回true,否則只返回false

(swap! atom
update-fn arguments
)對compare-and-set!的封裝,當返回false的時候會自動重試

(send agent
update-fn arguments
)

使用的線程池是(java.util.concurrent.Executors.newFixedThreadPool)線程個數是cpu個數+2

(send-off agent
update-fn arguments
)使用的線程池是(java.util.concurrent.Executors.newCachedThreadPool)
線程的個數按照實際需要分配

  

註:

1:Software Transactional Memory (STM):

STM事務裡面做的修改只能在事務提交之後才能被別的線程看到。這實現了ACID裡面的A(原子性)和I(隔離性)

事務開始之後,如果有別的線程對這個Ref做了改動,事務將會復原到開始的狀態,這就實現了C(一致性)

2:send 在分配一個action給Agent之後會立刻返回,action運行結束後,將傳回值賦值給Agent。
使用的線程池是(java.util.concurrent.Executors.newFixedThreadPool)線程個數是cpu個數+2
send-off與set類似,使用的線程池是(java.util.concurrent.Executors.newCachedThreadPool)
線程的個數按照實際需要分配。
當send,send-off 函數在事務裡調用的時候。該action會一直等到線程提交的時候才被發送給另外一個線程去執行。

 

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.