core.match with interaction between fields

94 views
Skip to first unread message

Emlyn Corrin

unread,
Jan 19, 2017, 9:10:36 AM1/19/17
to Clojure
Hi,
I have a series of map-like objects that I need to translate into keywords, and I've found core.match works really well for most cases, but there are a few cases where I need to match based on properties of combinations of fields, for example something like:

(match obj
  {:a 0, :b 0, :c _} :foo
  {:a 0, :b _, :c _} :bar
  {:a a, :b b, :c (+ a b)} :baz)

Except that's not valid, and results in the error: AssertionError: Invalid list syntax a in (+ a b).
I tried using a guard instead, like:

(match obj
  {:a 0, :b 0, :c _} :foo
  {:a 0, :b _, :c _} :bar
  {:a a, :b b, :c (_ :guard #(= % (+ a b)))} :baz)

But the bound symbols a and b are not available in the guard function: RuntimeException: Unable to resolve symbol: a in this context
Is there a way to do this with core.match? Or is there a better way?

Thanks in advance for any help.
Emlyn

Adam Clements

unread,
Jan 19, 2017, 12:18:31 PM1/19/17
to Clojure
Hey Emlyn!

For your specific example, couldn't you simply:
(match obj
  {:a 0, :b 0, :c _} :foo
  {:a 0, :b _, :c _} :bar
  {:a a, :b b, :c (+ (:a obj) (:b obj))} :baz)

I have hit this before myself and IIRC when I asked then, this is expressly not supported by core.match because of the particular way the macro expands for good performance. There are other pattern matching libraries which I think *do* support this though might not have the same performance profile as core.match. matchure is the one that springs to mind, though I think there were others.

Adam

--
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
---
You received this message because you are subscribed to the Google Groups "Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clojure+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Emlyn Corrin

unread,
Jan 19, 2017, 7:47:30 PM1/19/17
to Clojure
Hey Adam!

Thanks, that almost works - I can't put the + form in the pattern, as parentheses have special meaning in there, but I can just let it outside, like:
(let [aplusb (+ (:a obj) (:b obj))]
  (match obj
    {:a 0, :b 0, :c _} :foo
    {:a 0, :b _, :c _} :bar
    {:a a, :b b, :c aplusb} :baz))

I also have some cases with inequalities, for which I think I need to use guards, something like:
(match obj
  {:a 0, :b (_ :guard #(< % min_b))} :foo
  {:a 0, :b (_ :guard #(<= min_b % max_b)} :bar
  {:a 0, :b _} :baz
  ...)

Not the prettiest, but overall still much nicer (and hopefully efficient) than a huge condI might have a look into other pattern matching libraries, matchure looks like it might be a bit clearer for the :guard cases.

Cheers,
Emlyn
Reply all
Reply to author
Forward
0 new messages