<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    莊周夢蝶

    生活、程序、未來
       :: 首頁 ::  ::  :: 聚合  :: 管理

    Clojure的dosync是正則序?

    Posted on 2010-07-13 12:02 dennis 閱讀(2516) 評論(2)  編輯  收藏 所屬分類: 動態語言javaClojure

        解釋器求值的順序可以分為應用序和正則序,應用序是先求值參數,再執行表達式;正則序則是先將表達式按照實際參數展開,然后再執行。具體可以看看過去寫的這篇文章

       Clojure的求值可以肯定是應用序的,如執行
    (defn mytest [a b] 
          (
    if (= a 0)
              a
              b))
    (mytest 
    0 1/0)
            

    盡管在(mytest 0 1/0)中a綁定為0,如果求值器是完全展開再求值,那應該正常執行并返回a,也就是1;但是因為clojure是應用序,因此參數b的1/0會先計算,這顯然會報錯。

       clojure的dosync用于將一些表達式包裝成事務,Ref的更新操作沒有包裝在事務里,會拋出異常
    ;;定義mutable的Ref
     (def song (ref #{}))

    ;;添加一首歌
    (alter song conj 
    "dangerous")

       alter用于向Ref查詢并添加元素,用conj將"dangerous"這首歌加入集合,但是alter要求執行在一個事務里,因此上面的代碼會報錯
    java.lang.IllegalStateException: No transaction running (NO_SOURCE_FILE:0)

       如果你用dosync包裝就沒有問題
    user=> (dosync (alter song conj "dangerous"))
    #{
    "dangerous"}

       返回更新后的結果集合。這個跟我們要談的正則序和應用序有什么關系呢?可能你看出來了,如果說clojure是應用序,那么在表達式 (dosync (alter song conj "dangerous"))中,alter也應該先執行,應當照樣報" No transaction running"的錯誤才對,為何卻沒有呢?難道dosync是按照正則序執行?

       查看dosync的文檔
    user=> (doc dosync)
    -------------------------
    clojure.core
    /dosync
    ([
    & exprs])
    Macro
      Runs the exprs (in an implicit 
    do) in a transaction that encompasses
      exprs and any nested calls.  Starts a transaction 
    if none is already
      running on 
    this thread. Any uncaught exception will abort the
      transaction and flow out of dosync. The exprs may be run more than
      once, but any effects on Refs will be atomic.

       這是一個宏,他的作用是將表達式包裝在一個事務里,如果當前線程沒有事務,那么就啟動一個。
    查看源碼:

    (defmacro dosync
      
    "Runs the exprs (in an implicit do) in a transaction that encompasses
      exprs and any nested calls.  Starts a transaction if none is already
      running on 
    this thread. Any uncaught exception will abort the
      transaction and flow out of dosync. The exprs may be run more than
      once, but any effects on Refs will be atomic.
    "
      [& exprs]
      `(sync nil 
    ~@exprs))

       本質上dosync是調用了sync這個宏,sync干了些什么?
    (defmacro sync
      
    "transaction-flags => TBD, pass nil for now

      Runs the exprs (in an implicit 
    do) in a transaction that encompasses
      exprs and any nested calls.  Starts a transaction 
    if none is already
      running on 
    this thread. Any uncaught exception will abort the
      transaction and flow out of sync. The exprs may be run more than
      once, but any effects on Refs will be atomic.
    "
      [flags-ignored-for-now & body]
      `(. clojure.lang.LockingTransaction
          (runInTransaction (fn [] 
    ~@body))))

       找到了,原來是調用了clojure.lang.LockingTransaction.runInTransaction這個靜態方法,并且將exps包裝成一個匿名函數

    fn [] ~@body

         因此,dosync并非正則序,dosync是個宏,(dosync (alter song conj "dangerous"))展開之后,其實是
    (sync nil (fun [] (alter song conj "dangerous")))
       
         這就解答了為什么(dosync (alter song conj "dangerous"))可以正常運行的疑問。宏的使用,首先是展開,然后才是按照應用序的順序求值。


      





    評論

    # re: Clojure的dosync是正則序?  回復  更多評論   

    2010-07-14 19:16 by clojans
    只是函數調用時才說是應用序或正則序吧!

    # re: Clojure的dosync是正則序?  回復  更多評論   

    2010-07-14 20:30 by dennis
    @clojans
    恩,說的就是這么個事情,繞彎了
    主站蜘蛛池模板: 亚洲精品亚洲人成在线观看| 噜噜嘿在线视频免费观看| 久久精品国产亚洲一区二区三区 | 青青草原1769久久免费播放| 毛茸茸bbw亚洲人| 一级做a爱片特黄在线观看免费看| 成人亚洲综合天堂| 免费精品视频在线| 亚洲人成影院在线观看| 一级毛片无遮挡免费全部| 亚洲国产成人精品女人久久久 | 亚洲精品无码永久中文字幕| 美女网站在线观看视频免费的| 亚洲男人第一无码aⅴ网站| 污视频网站免费观看| 亚洲中久无码不卡永久在线观看| 一级成人毛片免费观看| 亚洲一区精品无码| 久别的草原电视剧免费观看| 亚洲视频免费观看| 成人免费网站在线观看| 色妞www精品视频免费看| 亚洲午夜久久久久妓女影院| 日本免费久久久久久久网站| 亚洲国产午夜精品理论片| 成人免费看黄20分钟| 一区二区三区在线观看免费| 久久精品亚洲综合| 成人免费无码大片a毛片| 国产精品福利片免费看| 78成人精品电影在线播放日韩精品电影一区亚洲 | 中文日韩亚洲欧美制服| 午夜电影免费观看| 一级视频免费观看| 久久久久亚洲精品天堂| 成人免费视频小说| 中文字幕无码免费久久| 亚洲精品天堂在线观看| 国产亚洲自拍一区| 9久9久女女免费精品视频在线观看| 色屁屁在线观看视频免费|