A few weeks ago I announced a pattern matching library called
matchure. I'm excited to say it's being merged into clojure.contrib as
clojure.contrib.match. I'd like some feedback on ideas for some
backward-incompatible changes I'm planning to make before it's
actually pushed to clojure.contrib.
In the discussion below, I'll use "matchure" when I'm speaking of the
current behavior, and "clojure.contrib.match" when I'm describing
proposed behavior of the library when it's merged in. See
http://github.com/dcolthorp/matchure/blob/master/README.md for an
introduction to matchure and the existing syntax, though I'll describe
the relevant before and after behaviors below.
Change 1: {:foo #"bar"} becomes {#"bar" :foo}
In matchure, maps test against the values of corresponding keys. I'm
going to change this so that the pattern is first and the key
second. This makes the behavior closer to let, makes
clojure.contrib.match more consistent in that patterns will always be
to the left of the matched value, and patterns like {even? :foo} read
better. This seems like an easy decision.
Change 2: Drop the question mark
In matchure, the question mark was meant to represent the matched
value. ? could act as a wildcard, ?foo acted as a wildcard that had
the side effect of storing the matched value in the variable foo, and
(odd? ?) tested the matched value for oddness. Though this can be
remembered easily (by me, at least), it doesn't fit in very well in
clojure, and I was thinking about giving each of those actions a
separate, more idiomatic representation. The new behavior would see _
as the only supported wildcard, simple symbols ("foo", not
"java.lang.String") bind variables always, and % would represent
the matched value in a list/function call pattern.
These changes together have a lot of nice interations. The
pattern-matching facility gets a lot closer to an extension of let:
for example, (let [{a :a} {:a 1}] a) and (if-match [{a :a} {:a 1}] a)
would do exactly the same thing (you'd use if-match if the matched
value may not meet all of the requirements). Function call forms will
share the same syntax as post-conditions. Pattern matching functions
become a lot more natural. For example, fib could be written
(fn-match this
([0] 1)
([1] 1)
([n] (+ (this (- n 1)) (this (- n 2)))))"
There are a few potential usability issues:
* it's easier to accidentally rebind a variable without performing a
test (which you may not realize until latert)
* you wouldn't be able to use list patterns inside #() functions
because of the overload of %
* unless other changes are made, you could accidentally rebind a class
name when you mean to do an instanceof test
My sense is that these shortcomings don't outweight the benefits
listed above. Does anyone else feel differently?
Also, binding variables by default means there needs to be a way of
specifying that a variable should act as a test value not as a
variable to be bound. I was thinking ~ (unquote) would serve this
purpose, so that (if-match [~foo x] true false) would test that (= foo
x)
and (if-match [foo x] foo) would always return x. This seems
natural to me, in that you're asking to match against the runtime
value of x instead of treating it as a static part of the pattern,
just like when using unquote in quasiquoted forms. (unquote x) would
work if you wanted to generate a matching form with a quasiquote.
Anyone have an opinion?
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to
clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to
clojure+u...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en