Skip to content

Instantly share code, notes, and snippets.

@AlexBaranosky
Created October 3, 2011 01:53
Show Gist options
  • Save AlexBaranosky/1258277 to your computer and use it in GitHub Desktop.
Save AlexBaranosky/1258277 to your computer and use it in GitHub Desktop.
macro to define match-based functions
(ns playmatch
(:use [clojure.core.match.core :only (match)]))
(defn len [coll]
"calc the length of a sequence"
(match [coll]
[[]] 0
[[f & r]] (inc (len r))))
(defmacro defmatch [name bindings & patterns]
"macro to make match-based functions"
`(defn ~name ~bindings
(match ~bindings
~@patterns)))
(defmatch len [coll]
[[]] 0
[[fst & rest]] (inc (len rest)))
(fact "voila!"
(len [\a \b \c]) => 3)
;; thoughts: that binding [coll] seems a little superfluous. With a more hairy/gnarly macro could gt rid of it, by inferring that length of each pattern's vector, and just making a vector from scratch to serve as the binding for the defn
;; That way we could just write:
(defmatch len
[[]] 0
[[fst & rest]] (inc (len rest)))
@AlexBaranosky
Copy link
Author

This macro is moving in the right direction:

(defmacro defmatch [name & patterns]
    `(defn ~name [abc#]
      (match [abc#]
      ~@patterns)))

;; it works for the example of:

(defmatch len
  [[]] 0
  [[fst & rest]] (inc (len rest)))

@AlexBaranosky
Copy link
Author

;;Playing with it I've come up with this code which Clojure barfs on:

(defn- n-gensyms [n]
  (take n (repeatedly gensym)))

(defmacro defmatch [name & patterns]
  (let [bindings# ~(n-gensyms (count (first (patterns))))]
    `(defn ~name bindings#
      (match bindings#)
      ~@patterns)))

@AlexBaranosky
Copy link
Author

(defmacro defmatch [name & patterns]
    (let [bindings (take (count (first patterns))
                          (repeatedly #(gensym "ocr-")))]
      `(defn ~name [~@bindings]
         (match [~@bindings]
           ~@patterns))))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment