David Nolen <dnolen.li...@gmail.com> writes:

Hi David,

>> In my patterns, I want to have a :+type key with a value that's
>> basically an interface name given as a symbol.  The pattern should
>> match, if the class of the object implements that interface (or an
>> extended interface thereof) directly or indirectly.  So that would be
>> my ideal user interface:
>>
>> --8<---------------cut here---------------start------------->8---
>> (match [obj]
>>  [{:+type 'Cat :mice 4}]   :1
>>  [{:+type 'Dog :cats 3}]   :2
>>  [{:+type 'Mammal}]        :3
>>  :else                     :nope)
>> --8<---------------cut here---------------end--------------->8---
>
> This is a known missing feature and there's a couple of open questions
> as far as how to best implement this.  It should probably support Java
> classes, Java interfaces, types, records, protocols and high
> performance hinted access to fields.

I'm not sure, if you've stopped reading there, so let me make my issue
clear.  I'm *not* especially interested in some new feature for
efficiently matching on types, although that wouldn't be bad either.

What I'd like to have was a way to influence when a certain key with a
certain value matches for my IMatchLookup extending custom type.  So if
IMatchLookup/val-at would be allowed to return a predicate that given
the value from the pattern tests if the match succeeds.

Here's a patch against the master version of core.match that makes my
Cat, Dog, Mamal example work, but it's only meant for illustration.

--8<---------------cut here---------------start------------->8---
--- a/src/main/clojure/clojure/core/match.clj
+++ b/src/main/clojure/clojure/core/match.clj
@@ -864,8 +864,12 @@
   (to-source* [this ocr]
     (cond
      (= l ()) `(empty? ~ocr)
-     (and (symbol? l) (not (-> l meta :local))) `(= ~ocr '~l)
-     :else `(= ~ocr ~l)))
+     (and (symbol? l) (not (-> l meta :local))) `(if (fn? ~ocr)
+                                                   (~ocr '~l)
+                                                   (= ~ocr '~l))
+     :else `(if (fn? ~ocr)
+              (~ocr ~l)
+              (= ~ocr ~l))))
   Object
   (toString [_]
     (if (nil? l)
--8<---------------cut here---------------end--------------->8---

I changed the LiteralPattern to-source* function to include a check if
ocr is a function.  In that case, I apply it to the value l, else I
stick to the usulal (= ocr l) comparison.  With that change, I can make
my val-at implementations return predicates like so:

--8<---------------cut here---------------start------------->8---
(extend-protocol IMatchLookup
  ;; ...
  de.uni_koblenz.jgralab.Vertex
  (val-at [this k not-found]
    (case k
      :+type     (fn [x]
                   ((core/type-matcher (graph this) x) this))
      ;; ...
      (match-attribute this k not-found))))))
--8<---------------cut here---------------end--------------->8---

That makes my Cat, Dog, Mammal example work fine.  But of course, it
works only for literal patterns, whereas my `type-matcher' function
above also accepts type specifications like [:and !Cat !Dog!] meaning
the object's type must be not a Cat and not exactly a Dog (but some Dog
subtype would be fine, and of course Birds, Fish, etc.).

So how would one tackle that issue in a general way?  I guess, we'd need
some new pattern type, PredicatePattern, right?  What might be a good
syntax for it?  If you beat me to it, I'd give it a shot.

Bye,
Tassilo

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@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+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Reply via email to