Hi everyone, I am trying to build a function to check if a data structure matches a pattern
(defmacro matches? [data pattern]
`(let [pattern# ~pattern]
(clojure.core.match/match [[~data]] [[pattern#]] true :else false)))
(let [data [1 1 1]
pattern '[1 1 _]
pattern2 '[1 1 1]]
[(matches? data pattern) (matches? data pattern2)])
The output of this
[false true]
Does anyone know why? And how can I build a matches? functionIn pattern, the _ bit is a symbol. When used in a macro, it remains a symbol value. So it's like you had (let [underscore (symbol "_")] ...) and pattern is actually '[1 1 underscore].
Whereas clojure.core.match/match must see _ as a literal part of the pattern - not as a symbol value inside the pattern value.
Is there a way to unquote the pattern before passing to core.match. I tried things like (second ~pattern) but that didn't work. During macro expansion pattern is just a symbol
It's not about unquoting, it's about values. You'd have to make the macro's code aware of all the local bindings available at the time the macro is expanded. And I don't think you can do it. See this question and following responses: https://clojurians.slack.com/archives/C03S1KBA2/p1603298420425300
Oh!! Thanks.. let me check
Well, for this particular case you can use something like this:
(defmacro matches? [data pattern]
(let [pattern (if (symbol? pattern)
(.eval (.-init (&env pattern)))
pattern)]
`(clojure.core.match/match [[~data]] [[~pattern]] true :else false)))
But don't do it. It breaks everything that's not clojure.lang.Compiler, even macroexpand doesn't work with the above macro.
And it won't work with anything that's not a constant, so while '[...] works, (vector ...) doesn't.It works but &env thing is very new to me. I think of some other way of doing things.
Since clojure.core.match/match is a macro and you seem to need run-time patterns, it's just not a suitable thing to use, at all.
I don't really know what a suitable alternative would be. But it would somehow have to be able to differentiate between "symbol as a value" and "symbol as a placeholder".
match is suitable if you can remove the need for run-time patterns and be content with patterns that exist during macro expansion time.
I am thinking of simply doing tree traversal and comparing each element. I am building this function for dev time debugging/data exploration, so performance is not a big deal.
If you can devise a grammar for your data you could use instaparse. But maybe it's a "shot with cannons on sparrows".
I'm traversing a graph recursively depth first and I'm building the result in an accumulator. I want to return a vector as insertion order is relevant for the result. On the other hand, each entry should be included only once. My first idea was to have the vector for the result and a set for deduplication in the accumulator. Another option would be to deduplicate the returned vector (maybe also using a set). How would you handle this insertion ordered result?
I would go with vector + set.
Or an ordered set from https://github.com/frankiesardo/linked.
How about java.util.LinkedHashSet https://docs.oracle.com/javase/8/docs/api/java/util/LinkedHashSet.html
Or that, if mutable data is fine and compatibility with CLJS or other targets is not needed.
I would consider accumulating to the vector using a distinct transducer. This code snippet illustrates what I mean:
user=> (let [conj-distinct ((distinct) conj)]
(reduce conj-distinct [] [1 2 3 2 1 2 3 6 3 6 7]))
[1 2 3 6 7]
Edited to use let.You would have to lug the same transducer around, since it's stateful.
Just make sure to not reuse conj-distinctoutside the scope of the algorithm since it is stateful.
I would then put it at the boundary of the algorithm just before returning the result or even completely outside. Thanks for the ideas, now I have a few options to think about.
You would instantiate conj-distinct every time you instantiate an empty vector into which you accumulate the result. But maybe the easiest is to just pick one of the options that others have already suggested.
I've used https://github.com/quoll/tiara a few times with success. In particular, ordered-set may be of use.
Hi! I have popped into this tutorial (https://ericnormand.me/guide/clojure-web-tutorial) and in it the author mentions the part 2. Does anyone know if it is already published and the URL?
No I never finished it
Thanks @seancorfield @ericnormand for the replies and Eric for the tutorial the first part, almost finished.