2016-08-20 58 views
1

我正在將Scheme中的一些代碼翻譯成Clojure。 方案代碼使用名爲pmatchhttps://github.com/webyrd/quines/blob/master/pmatch.scm)的宏將匹配參數設置爲輸出表達式。具體而言,它允許可變捕獲如下:Clojure模式匹配宏與變量arity,超越了明確的匹配情況

(define eval-expr 
    (lambda (expr) 
    (pmatch expr 
     [(zero? ,e) 
     (zero? (eval-expr e))) 
... 

在該使用實例中,一些輸入表達式eval-expr'(zero? 0),應該匹配的第一例。列表的車匹配zero?和輸入匹配。因此,0綁定到e並傳遞給(zero? (eval-expr e)),並且此expr是遞歸計算的。 在Haskell,它支持原生模式匹配,代碼可能轉換爲類似以下內容:

Prelude> let evalexpr "zero?" e = (e == 0) -- ignoring recursive application 
Prelude> evalexpr "zero?" 0 
True 

在Clojure中,我第一次嘗試用core.match(https://github.com/clojure/core.match),寫由大衛·諾倫替代pmatch和其他人,但是,據我所知,這個宏似乎

  1. 只支持每次使用參數的單元數
  2. 僅支持明確的匹配,而不是基於屬性的匹配(可作爲後衛)

我正在嘗試的另一個選擇是名爲defunhttps://github.com/killme2008/defun)的較少已知的宏,它定義了模式匹配函數。這裏有一個例子:

(defun count-down 
    ([0] (println "Reach zero!")) 
    ([n] (println n) 
    (recur (dec n)))) 

我還在探索defun,看看它是否給了我需要的靈活性。 同時,有沒有人有如何在Clojure模式匹配的建議1.柔性陣列2.變量捕獲?

回答

3

忽略遞歸應用:

(ns test.test 
    (:require [clojure.core.match :refer [match]])) 


(def v [:x 0]) 

(def w [:x :y 0]) 

(defn try-match [x] 
    (match x 
     [:x e] e 
     [:x expr e] [expr e] 
     )) 

(try-match v) 
;; => 0 

(try-match w) 
;; => [:y 0] 


;; Matching on lists (actually, any sequences) 

(defn try-match-2 [exp] 
    (match exp 
     ([op x] :seq) [op x] 
     ([op x y] :seq) [op x y])) 

(try-match-2 '(+ 3)) 
;; => [+ 3] 

(try-match-2 '(+ 1 2)) 
;; => [+ 1 2] 

詳情請參閱https://github.com/clojure/core.match/wiki/Overview

此外,我建議你仔細看看Clojure destructuring。很多事情可以用它來完成,而不是訴諸於core.match,實際上你的用例已經被覆蓋了。

+0

謝謝你的迴應。你介意提供額外的解釋嗎? –

+1

當然,我不介意,只是請讓我知道什麼不清楚?我特別提供了一個你稱之爲「靈活的元組」的例子 - 變長模式和變量綁定(你稱之爲「變量捕獲」)。它似乎直接解決你的用例,除非我錯過了一些東西。 –

+0

你有沒有機會知道如何將你的例子的邏輯擴展到列表? (例如(try-match'(+ 2 2))=> 4) –