2012-05-21 74 views
8

我有時會發現在Clojure中定義簡化的函數版本,並返回部分函數(例如,定義減少的部分函數

(defn prefix 
    ([pre string] 
    (str pre ":" string)) 

    ([pre] 
    (fn [string] 
     (prefix pre string)))) 

這意味着,你可以做兩種:

(prefix "foo" 78979) 
=> "foo:78979" 

((prefix "foo") 78979) 
=> "foo:78979" 

這似乎相當哈斯克爾十歲上下,並避免了需要partial創造的部分功能。

但在Lisp中它被認爲是良好的編碼風格/ API設計嗎?

+0

這是咖啡,是嗎?看起來很有用。我認爲這裏的界面可以改進。如果你能使這種技術具有通用性,那將是很好的;也就是說,對於具有所有關鍵字的函數,如果您使用一組不完整的關鍵字調用該函數,它將返回一個閉包,該閉包接受所有剩餘的關鍵字。如果所有關鍵字都被使用了,那麼你得到了這個函數的值。我可以看到這被用作優化技術。 –

+0

我認爲它仍然是一個意識形態,如果你給它定義可讀性的偏見,當你這樣定義它們時:(def prefix(partial ...))所以這裏有兩個參數:一個引用的名字,它是顯式的。請注意,您現在不使用defn,但是def-partial正在爲您創建函數 – KIMA

回答

7

在功能默認爲curried的語言中,函數調用也是curried。當你寫 (f a b c)時,該語言將其解釋爲(((f a) b) c)。在Clojure中情況並非如此。

我相信,在調用默認情況下不令行禁止的環境使咖喱功能創建一個概念上的不匹配 - (我的意思是你的代碼的人看懂)這個結構可能會引起讀者的混淆

如果你的函數有兩個以上的論據,這個定義很快就變得醜陋了。假設一個函數有4個參數。爲了完全模擬currying調用,當有人第一次傳遞2個參數,然後剩下的兩個參數時,您需要處理((f a b) c d)這樣的情況。在這種情況下,雙參數函數的重載版本需要返回一個重載函數,該函數的行爲有所不同,具體取決於它是否獲得1或2個參數。我想可以用宏自動化,但仍然可以。

此外,你殺死定義默認參數和& rest構造的可能性。

+0

默認參數和可變參數'&rest'函數 – 6502

+0

@ 6502是的。編輯完整性。 –

6

嗯......個人而言,我寧願看partial,因爲這說明了發生了什麼事情。

我不知道它是「好」還是「壞」的編碼風格,但我從來沒有在現有的Clojure代碼中見過這種風格,我可以想象使用API​​的人會期望(prefix "foo" 78979)(prefix "foo")返回相同類型的對象。

賺取差價之間的這兩個功能明確,你可以做這樣的事情,而不是:

(defn prefix [pre string] 
    (str pre ":" string)) 

(defn prefix-fn [pre] 
    (fn [string] 
    (prefix pre string))) 

(prefix "foo" 78979)  ; => "foo:78979" 
((prefix-fn "foo") 78979) ; => "foo:78979" 
+2

「我從來沒有在現有的Clojure代碼中看到過這種風格」 - 它已經遍佈Hickey的新reducer庫。 –

+0

你是對的,謝謝你指出。 – Gert

9

使用partial創造咖喱功能是基於明確的概念是更好(在大多數情況下: ))。我發現這個概念在Clojure,Python等動態類型語言中更適用/使用可能是因爲缺少類型簽名/靜態類型,所以將事情明確化更有意義。