2017-08-17 53 views
2

思考功能類似,但在Clojure中,這是更好,更performatic,少重於JVMClojure的讓VS多參數數量

(defn- on-message 
    ([options ch {:keys [headers delivery-tag]} ^bytes payload ^CompanyProto$Company$Builder company] 
    (check-id company) 
    (save company options) 
    (basic/ack ch delivery-tag)) 
    ([options ch ^PersistentHashMap kwargs ^bytes payload] 
    (on-message options 
       ch 
       kwargs 
       payload 
       (-> (CompanyProto$Company/newBuilder) 
        (.mergeFrom payload))))) 

(defn- on-message [options ch {:keys [headers delivery-tag] ^bytes payload}] 
    (let [company (-> (CompanyProto$Company/newBuilder) (.mergeFrom payload))] 
    (check-id company) 
    (save company options) 
    (basic/ack ch delivery-tag))) 
+1

有沒有理由爲什麼你正在考慮多元化的第一個選項?除非該方法是從其他地方同時使用兩個簽名調用的,否則第二個(使用綁定)肯定不那麼混亂。我相信你也可以在堆棧中保存一個呼叫,這看起來像是一個多層次的呼叫。 –

+0

@ToniVanhala @ToniVanhala我首先做了,但一位朋友說let是壞的並且沒有功能(他是一個erlang開發者),我是功能性的新郎......他說的另一件事就是那個clojure很奇怪不是無堆棧 –

+0

[「let」表達式可能被認爲是應用於值的lambda抽象](https://en.wikipedia.org/wiki/Let_expression),所以它適合函數式編程。 –

回答

0

您的直接問題的答案是,函數調用中沒有引入開銷,只是因爲該函數碰巧具有多個元素。在Clojure中,所有的函數調用都被編譯成一個方法調用。調用的確切方法取決於參數的數量 - 就JVM而言,每個元素都被編譯爲不同的方法。確定調用哪個方法是在編譯時進行的,所以在運行時沒有開銷。

這就是說,嵌套函數調用有一些開銷。具體而言,每次調用都會使調用堆棧增長一個常量,直到該調用返回。但是,這種開銷很小,在這種情況下不可能對性能產生可衡量的影響。

@ToniVanhala我做了讓第一,但朋友說,讓壞 ,而不是功能性的(他是一個Erlang的開發者),我在功能 LANGS新......另一件事是他說是奇怪,那個clojure是 沒有堆疊

這似乎是真正的問題。所以這是值得解決的。

let只是一個表達式,它允許我們將值綁定到變量。這些綁定是不可變的。此外,衆所周知,let可以實現爲lambda上的宏抽象(或者,在Clojure的詞彙表中,fn)。所以let肯定沒有任何關於它「不起作用」的東西。

Clojure沒有堆疊也沒有什麼「奇怪」或令人費解。 Clojure是一種JVM語言,並且調用堆棧深深嵌入JVM的抽象計算模型中。雖然有辦法解決這個問題(例如,continuation-passing風格),但這些方法要麼放棄深層JVM互操作性和/或支付性能損失。 Clojure首先是一種務實的語言,這是一種務實的讓步。

此外,Clojure(作爲一個Lisp)是一個真正的語言框架,您可以用它來僞造您想要的語言。你的語言可能會做出不同的折衷。例如,您的語言可能是"stackless"。或者它可能有first-class continuations(免責聲明:我是pulley.cps的作者)。或者它可能有completely different paradigm(即邏輯vs功能)。但它也可以非常簡單。使用Clojure,您可以選擇您支付的費用。具有諷刺意味的是,你的朋友是正確的代碼不能正常工作。但是,這不是因爲let。相反,幾乎所有的東西除了let不起作用。例如,(save company options)顯然是一個副作用的操作。然而,這並不意味着你的代碼是壞的 - 即使是最純粹的功能程序,在某種程度上,如果它具有任何實際價值,它們也必須與真實世界相互作用。

+0

這是一個完整的答案,謝謝你,我想知道你是否可以展示一些例子,正如我所說我是功能性的新手,我真的想學習它,我不明白如何保存在那裏功能... –

+0

@RafaelCustódio,「純」功能編程編程沒有副作用。如果你仔細想想,「保存」/必須是副作用,或者這個調用是完全多餘的,應該被消除。原因很簡單(但不一定非常明顯) - 由'save'返回的值永遠不會被使用。因此,對'save'的調用只有在執行一些副作用(例如在數據庫中存儲某些內容)時纔有意義。 (續) –

+0

再次(我不能強調這足夠),我不是說你的代碼是壞的是任何方式。事實上,我認爲它看起來相當合理 - 沒有辦法可以寫入沒有副作用的數據庫。但它確實意味着你的代碼在技術上不是「功能」(從最純粹的意義上說)。希望有所幫助。 –

1

如果您在使用Java進行開發互操作,將*warn-on-reflection*設置爲true。如果有警告,您需要用提示消除它。然後你就可以得到「有代表性的,對JVM不太重的」代碼。

P.S.數學計算具有可變性,簡單的JVM類型和未檢查的溢出是另一回事,如果這是您的情況,您也需要檢查這一點。

+0

感謝您的提示,因爲我正在使用一些Java類,我會這樣做,但是在哪裏?在Core.clj中? –

+0

@RafaelCustódio,'(set!* warn-on-reflection * true)'在具有這些功能的源文件中。也可以用'(:gen-class)'來創建這個命名空間。 – fevgenym

+0

感謝@fevgenym –