2016-08-20 43 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) –