-
Notifications
You must be signed in to change notification settings - Fork 55
This issue was moved to a discussion.
You can continue the conversation there. Go to discussion →
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use of memory vars in map/set literals are subject to Clojure semantics (order not preserved except for small values) #97
Comments
I disagree then semantics are undefined in such cases, however, I would agree they are nondeterministic and hear your concern. It is well known that map literals are read by the reader as either I agree with your concern that a warning/error might "prove too restrictive to cases where one does not care about order" and further add that I think it would be difficult to determine the set of patterns involving memory variables and Going back to ordering problem, the common prescription for constructing a large, insertion ordered map is to use the (apply array-map '(k l m n o p q r s t a b c d e f g h i j ))
;; => {k l, m n, o p, q r, s t, a b, c d, e f, g h, i j}
(class *1)
;; => clojure.lang.PersistentArrayMap Perhaps we could do something similar and thus could compromise in the following ways.
|
Oh yes, "nondeterministic" is a much better way of putting what I had in mind, thanks for clarifying that :)
That's definitely true, my first thought of a heuristic was something like the following (when (map? pattern)
(let [mvar-sets
(for [[k v] pattern
:when (not= '& k)]
(set (concat (extract-mvars k) (extract-mvars v))))]
(assert (pairwise-disjoint? mvar-sets)))) The other options also sound good, I admit it's not much of an issue to someone familiar with Clojure's reader, and I only came across it while thinking about the implications of memory var semantics. So maybe introducing a new operator just to support this edge-case isn't necessary? |
Given nothing can be done about the Clojure reader, disallowing memory variables in maps seems reasonable to me. It seems to me that whenever you encounter an "non-entity map" in meander you are almost always better off treating it as a sequence of key-value pairs. This is achieved with Match only maps to (m/rewrite
{1 2 3 4}
(m/kvs ([!k !v] ...))
(m/kvs ([!v !k] ...))) Alternatively, is it possible to make the (m/rewrite {1 2 3 4}
{& ([!k !v] ...)}
{& ([!v !k] ...)}) This has the advantage of visually queuing me in that its a map, but right now it doesn't work (not sure why... should it work??) |
There are plenty of cases where memory variables in map patterns are specifically useful, convenient, and deterministic. Eliminating them because they're unpredictable in certain situations is not a solution.
I believe you're asking if we could make match support that syntax and I think, yes, we could. Another way to get the symmetry you crave with the (defsyntax map-of [k-pattern v-pattern]
(cond
(match-syntax? &env)
`(with [%map# {~k-pattern ~v-pattern & (or '{} %map#)}]
%map#)
(subst-syntax? &env)
`(with [%map# {~k-pattern ~v-pattern & %map#}]
%map#)
:else
&form)) Using your example (m/rewrite {:foo "bar", :baz "quux"}
(m/map-of !k !v)
(m/map-of !v !k))
;; =>
{"quux" :baz, "bar" :foo} One thing to note about the {& [[!k !v] ...] will not. I think this is also fine, however, I do want to make sure that detail is flagged. |
Based on conversations in other topics I just want to regroup on where your thinking is at on this specific subject as there were several proposals which I think at this point can be thinned out.
1.a. Match does however already support
|
This issue was moved to a discussion.
You can continue the conversation there. Go to discussion →
The interaction between Meander's "left-to-right, top-to-bottom" evaluation strategy and the unordered nature of Clojure's map and set literals could cause the following type of edge case:
This appears to work fine until more than 8 elements are introduced, causing Clojure to switch from an ordered ArrayMap to unordered HashMap implementation.
@noprompt and @jimmyhmiller suggested using
&
syntax on RHS to guarantee evaluation order:And similarly
m/and
on the LHS:{1 !n ,,, 9!n}
->(m/and {1 !n} ,,, {9 !n})
I suggest introducing a check during compilation that would detect if the same memory-var is being referenced across more than one branch of a map or set literal, and then flag it as a warning/error due to the undefined semantics. (hopefully this does not prove too restrictive to cases where one does not care about order)
The text was updated successfully, but these errors were encountered: