下面是我編寫的一些代碼,使用clojure.core.match,它執行相當常見的編程任務。一個函數需要一些「命令」(或「對象」,「記錄」或任何你喜歡稱之爲的東西),必須對每種類型做一些不同的事情,並且必須對它們進行解構以準確地確定要做什麼以及不同的命令類型可能會以不同的方式解構:在Clojure中解構命令的習慣性方式
(defn action->edits [g action]
"Returns vector of edits needed to perform action in graph g."
(match action
[:boost from to]
[[:add-edge from to 1.0]]
[:retract from to]
[[:remove-edge from to]]
[:normalize from to] ; a change has just been made to from->to
(map (fn [that] [:remove-edge from that])
(successors-except g from to))
[:recip-normalize to from] ; a change has just been made to from->to
[]
[:reduce-to-unofficial from to competitor]
[[:remove-edge from to] (make-competitive-edge from competitor]))
我主要模仿了人們通常使用方案的pmatch宏。我想知道在Clojure中做這件事的慣用方式是什麼。
這就是我喜歡上面的代碼:
這是非常可讀性。
這很容易寫。
這裏就是我不喜歡:
從任何地方訪問
from
和to
領域但match
宏內部是非常不可讀的,而且容易出錯。例如,要從大多數動作向量中提取from
元素,請編寫(action 1)
。如果我添加了新的動作,那麼該代碼將會中斷,並且現在在:recip-normalize
中斷。由
match
生成的代碼效率低下:它通過重複拋出和捕獲異常來進行搜索。它不會產生一個大的嵌套if
。
我嘗試一點與代表命令,地圖,但它似乎變得冗長,以及命令的名稱並不突出好,大大降低了可讀性:
(match action
{:action :boost :from from :to to}
[{:edit :add-edge :from from :to to :weight 1.0}]
{:action :retract :from from :to to}
[{:edit :remove-edge :from from :to to}]
. . .)
可能未來版本的match
將生成更好的代碼,但現在生成的糟糕代碼(以及缺乏對記錄的支持)表明,在Clojure中,人們多年來一直在愉快地處理這種事情,而沒有match
。那麼如何在Clojure中做這樣的事情?做什麼?
爲什麼不'(DEFN動作 - >編輯[G [行動英尺]'和'(condp =行動:提升 「助推」',還是我失去了一些東西 - 換句話說,爲什麼不首先解構fn參數? – birdspider
@birdspider謝謝,'condp'可能正是我需要的!我只用了幾天的Clojure,因此我寫了「Clojure中的Scheme」。發表一個答案!順便說一句,在我的例子中,所有的記錄看起來都有相同的兩個參數。通常當我做這種事情時,他們會有所不同。我現在修改這個例子,因爲我對這個成語很感興趣對於如何解構變體記錄 - 但在我的實際代碼中,我會像使用通用模式一樣利用你建議。:) –