Reputation: 3381
I'm in the process of translating some code from Scheme to Clojure.
The Scheme code uses a macro called pmatch
(https://github.com/webyrd/quines/blob/master/pmatch.scm) to pattern match arguments to output expressions. Specifically, it allows for variable capture as follows:
(define eval-expr
(lambda (expr)
(pmatch expr
[(zero? ,e)
(zero? (eval-expr e)))
...
In this use example, some input expression to eval-expr
, '(zero? 0)
, should match the the first case. The car of the list matches to zero?
and the arity of the input matches. As a consequence, 0 is bound to ,e and passed to (zero? (eval-expr e))
, and this expr is evaluated recursively.
In Haskell, which supports pattern matching natively, the code might translate to something like the following:
Prelude> let evalexpr "zero?" e = (e == 0) -- ignoring recursive application
Prelude> evalexpr "zero?" 0
True
In Clojure, I first tried to substitute pmatch with core.match (https://github.com/clojure/core.match), which was written by David Nolen and others, but, to my knowledge, this macro seems to
Another option I'm trying is a lesser known macro called defun
(https://github.com/killme2008/defun), which defines pattern matching functions. Here's an example:
(defun count-down
([0] (println "Reach zero!"))
([n] (println n)
(recur (dec n))))
I'm still exploring defun to see if it gives me the flexibility I need. Meanwhile, does anyone have suggestions of how to pattern match in Clojure with 1. flexible arity 2. variable capture?
Upvotes: 1
Views: 408
Reputation: 2698
Ignoring recursive application:
(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]
See https://github.com/clojure/core.match/wiki/Overview for more details.
Additionally, I suggest you have a close look at Clojure destructuring. Lots of things can be done with it without resorting to core.match
, actually your use case is covered.
Upvotes: 3