具有可变arity的Clojure模式匹配宏超出了显式匹配案例

时间:2016-08-20 18:53:40

标签: clojure macros pattern-matching

我正在将一些代码从Scheme翻译成Clojure。 Scheme代码使用一个名为pmatchhttps://github.com/webyrd/quines/blob/master/pmatch.scm)的宏来模拟匹配参数到输出表达式。具体来说,它允许变量捕获如下:

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

在此用例中,eval-expr'(zero? 0)的某些输入表达式应与第一种情况匹配。列表的汽车与zero?匹配,输入的arity匹配。因此,0绑定到e并传递给(zero? (eval-expr e)),并且递归地计算此expr。 在本机支持模式匹配的Haskell中,代码可能会转换为如下所示:

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

在Clojure中,我首先尝试将pmatch替换为由David Nolen和其他人编写的core.match(https://github.com/clojure/core.match),但据我所知,这个宏似乎

  1. 每次使用只支持一个参数ar
  2. 仅支持显式匹配,而不支持基于属性的匹配(可用作警卫)
  3. 我正在尝试的另一个选项是名为defunhttps://github.com/killme2008/defun)的鲜为人知的宏,它定义了模式匹配函数。这是一个例子:

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

    我仍在探索defun,看看它是否给了我所需的灵活性。 同时,是否有人建议如何在Clojure中进行模式匹配1.灵活的arity 2.变量捕获?

1 个答案:

答案 0 :(得分: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,实际上您的用例已被覆盖。