Skip to content

Instantly share code, notes, and snippets.

@pepijndevos
Created April 28, 2011 17:48
Show Gist options
  • Save pepijndevos/946857 to your computer and use it in GitHub Desktop.
Save pepijndevos/946857 to your computer and use it in GitHub Desktop.
seqex - a tiny pattern matcher in Clojure
(defproject seqex "1.0.0-SNAPSHOT"
:description "a tiny pattern matcher"
:dependencies [[org.clojure/clojure "1.2.1"]]
:source-path ""
:aot [seqex]
:omit-source true)
(ns seqex
(:import [clojure.lang
Fn
IPersistentVector
IPersistentMap]))
(defn cps [funct cont]
(fn [[f & r]]
(when-let [f (funct f)]
(when-let [r (cont r)]
(if (true? r)
(if (true? f) [] [f])
(if (true? f) r (cons f r)))))))
; (and (funct f) (cont r))))
(def _ (constantly true))
(def end nil?)
(defmulti matcher type)
(defn match [pattern items]
((reduce #(cps (matcher %2) %1)
(rseq pattern))
items))
(defmethod matcher :default [l]
(partial = l))
(defmethod matcher Fn [f] f)
(defmethod matcher IPersistentVector [pattern]
(partial match pattern))
(defmethod matcher IPersistentMap [pattern]
(fn [m]
(every? identity
(for [[k v] pattern]
(when-let [mv (get m k)]
((matcher v) mv))))))
(defmethod matcher java.util.regex.Pattern [pattern]
(partial re-find pattern)) ; returns match
(defn store [pattern]
(fn [s]
(when ((matcher pattern) s)
s)))
(defmacro cond-let
[& clauses]
(when clauses
(list `if-let (first clauses)
(if (next clauses)
(second clauses)
(throw (IllegalArgumentException.
"cond-let requires an even number of forms")))
(cons `cond-let (next (next clauses))))))
(match
[1
[3 _ end]
{:a even?, :b #(= 2 (count %))}
end]
[1 [3 5] {:a 4, :b [1 2], :d :a}])
; [] (is truthy)
(match [1 2 3 _] [1 2 3 4 5 6 7 8])
; []
(let [[x y] (match
[1 #"\w.+?\w" 3 (store _) end]
[1 "foo bar" 3 4])]
(dotimes [_ y] (println x)))
; foo
; foo
; foo
; foo
; nil
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment