Wishful Coding

Didn't you ever wish your computer understood you?

Clojure micro pattern matcher

Today I had some ideas for my game related to cellular automata that involved pattern matching. I googled, and found Matchure.

It might be a great pattern matcher, but the syntax and the amount of macro trickery makes me feel uncomfortable.

In an attempt to write one that relies only on functions, I made this.

Update: This is now a cute project-in-a-gist that can be used as a checkout dependency in Leiningen and Cake.

(ns seqex
(:import [clojure.lang

(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))

(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)

(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))))))
[3 _ end]
{:a even?, :b #(= 2 (count %))}
[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
(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)

Pepijn de Vos