2013-03-23 66 views
4
;; Once upon a time I opened a REPL and wrote a protocol 
;; definition: 
(defprotocol SomeProtocol 
    (f [this])) 

;; And a record: 
(defrecord SomeRecord [] 
    SomeProtocol 
    (f [this] 
    "I don't do a whole lot.")) 

;; And a very useful side-effect free function! 
(defn some-function [] 
    (f (SomeRecord.))) 

;; I call my function... 
(some-function) 
;; ...to see exactly what I expect: 
;; user=> "I don't do a whole lot." 

;; Unsatisfied with the result, I tweak my record a little bit: 
(defrecord SomeRecord [] 
    SomeProtocol 
    (f [this] 
    "I do a hell of a lot!")) 

(some-function) 
;; user=> "I don't do a whole lot." 

看起來像一個bug給我。在C++用戶組中看到如此多的錯誤編譯器錯誤報告之後,我只是不能確定。奇怪的意外defrecord行爲:一個錯誤或功能?

回答

6

重新定義記錄後需要重新定義some-function。原因是defrecord創建了一個新類型(使用deftype),並且在函數內部使用(SomeRecord.)表示法將代碼綁定到該類型,即使在定義了具有相同名稱的新類型之後。這就是爲什麼它通常更喜歡使用(->SomeRecord)表示法來實例化記錄,使用這種表示法可以使您的代碼按預期工作。

+0

謝謝你的回答!你能詳細說明'(SomeRecord。)'和'( - > SomeRecord)'之間的區別嗎? – igr 2013-03-23 19:20:04

+0

''(SomeRecord。)'是一種被翻譯成特殊格式'(新SomeRecord)'的讀者宏。由於它是一種特殊的形式,因此在這種情況下可能不遵循看似明顯的規則。我想'(新SomeRecord)'被翻譯成內部的東西,比如'(new package.SomeRecord $ some_unique_identifier)'。 '( - > SomeRecord)'OTOH只是一個由'(defrecord)'定義的函數。當你重新定義你的記錄時,它保留了Clojure的名字而不是內部名字,所以構造函數的調用變得過時了,但函數只是用新的含義重新定義,所以調用它仍然有效。 – 2013-03-23 19:45:19

+0

這很有道理。謝謝! – igr 2013-03-23 20:17:01