Fork me on GitHub
#clojure
<
2022-09-24
>
oskarkv12:09:53

When using clojure.tools.macro/symbol-macrolet, it won't expand symbols inside special forms. Like this:

user> (macroexpand '(symbol-macrolet [name my-new-name]
                      (def name 1)
                      (something-else name)))

(do (def name 1) (something-else my-new-name))
I find it annoying. But maybe there is a good reason for it. Does anybody have any idea of why it works this way?

oskarkv13:09:44

Actually it's not everything inside special forms. But it just won't expand the first arg of def.

Noah Bogart14:09:45

As I mentioned a couple weeks ago in #rewrite-clj, I’m building a pattern-matching library for rewrite-clj/clj-kondo nodes: convert an s-expression into a function that checks if a given node matches the s-expression. I’ve got it all working for tokens (nil, boolean, keyword, symbol, string), lists, and vectors, but I’m struggling to get an algorithm for matching against maps (and sets) that contain non-tokens (lists, vectors, maps, sets). The issue I’ve run into is that map nodes aren’t map objects but an ordered seq of nodes of keys and values: {:type :map :children [{:type :token :k “asdf”} {:type :token :lines [“some val”]}] I have a couple of thoughts and questions about this: I can’t simply convert a map node to a clojure map because if a key is a non-token, what do I make the key? The entire :children seq? That falls apart quickly, so I imagine I’ll leave it as a map node. How do I write a matcher that checks if the map node contains a non-token? (For example, the map pattern contains the pair [[1 2 3] :key].) The match predicate needs to find a matching key in the map node’s :children and then remove or track that it’s been matched. Does that mean potentially calling the match predicate on every key in the map node’s :children? Seems like it would be computationally inefficient. Given all of that, is there an efficient method of checking if all elements in one seq (the map pattern) are in another seq (the :children of the map node)? Are there other ways of doing this I’m missing?

Martynas Maciulevičius16:09:48

What if you would wrap everything? Primitives too. I don't completely understand your problem but I think that you may want to wrap everything so that you would always operate on wrapped items. This way you would have wrapped items inside wrapped items. :thinking_face: And that could allow to use the same methods on all of them.

Noah Bogart16:09:34

I think that’s adjacent to my question. The nodes are already wrapping the input string (rewrite-clj reads in a string, spits out parsed nodes). Even if I further wrap the nodes, inside of the wrapping logic I’ll need to perform some algorithm to determine if the map pattern is a subset of the input map node

Martynas Maciulevičius16:09:43

Could you provide a sample input? Also why can't you take keys from the smaller map using keys, then use select-keys in the big map and check if both maps are the equal? This should negate need for ordering. But it will expect deterministic node creation.

Noah Bogart16:09:07

Yeah, I can provide an example, gimme a bit

Martynas Maciulevičius17:09:22

Why can't this work?

(defn check [m-small m-large]
  (= m-small
     (select-keys m-large (keys m-small))))
Then you'd need to make sure that your maps create nodes in a deterministic way.

lread22:09:05

So you probably know this @UEENNMX0T, but you’ll want to keep things in node form and not use sexpr.

👍 1
Noah Bogart22:09:15

Right, maybe i misspoke. I’m consuming an input sexpr as a pattern to create a matching function. The matching function consumes nodes and does not transform it to a sexpr

lread22:09:27

> Does that mean potentially calling the match predicate on every key in the map node’s :children? Seems like it would be computationally inefficient. I think so. Maybe start with that and figure out if you need to optimize later. Also be aware that rewrite-clj will read/write unbalanced maps, by this I mean: {:a 1 :b}.

😬 1
Noah Bogart22:09:29

That’s great to know, thanks

👍 1