<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Clojure Q&amp;A - Recent questions and answers in core.unify</title>
<link>https://ask.clojure.org/index.php/qa/contrib-libs/core-unify</link>
<description></description>
<item>
<title>Answered: core.unify doesn't handle maps correctly</title>
<link>https://ask.clojure.org/index.php/14147/core-unify-doesnt-handle-maps-correctly?show=14153#a14153</link>
<description>&lt;p&gt;I've got the following patch for consideration. it works in two phases:&lt;br&gt;
1. It identifies any keys which are &quot;not complex&quot;. Complex here meaning a variable, or some kind of collection. These are keys that presumably can be matched on equality and not need unification. Probably the most common type.&lt;br&gt;
2. Complex keys that need unification and backtracking. &lt;/p&gt;
&lt;p&gt;I think there might be one weakness in the patch in that it considers &lt;code&gt;x&lt;/code&gt; to be a template and &lt;code&gt;y&lt;/code&gt; to be the concrete values and this is not true.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;diff --git a/src/main/clojure/clojure/core/unify.clj b/src/main/clojure/clojure/core/unify.clj
index a89db73..c53a0c7 100644
--- a/src/main/clojure/clojure/core/unify.clj
+++ b/src/main/clojure/clojure/core/unify.clj
@@ -101,6 +101,36 @@
   (and (composite? form)
        (#{'&amp;amp;} (first form))))
 
+(defn- garner-unifiers-map
+  [uv-fn variable? x y binds]
+  (let [complex-key? (some-fn variable? composite?)
+        concrete-ks  (-&amp;gt;&amp;gt; x keys (filter (complement complex-key?)))
+        simple-binds (reduce (fn [binds k]
+                               (garner-unifiers uv-fn variable?
+                                                (find x k)
+                                                (find y k)
+                                                binds))
+                             binds
+                             concrete-ks)]
+    (if (or (nil? simple-binds) (every? (complement complex-key?) (keys x)))
+      simple-binds
+      (letfn [(solve [x y binds]
+                (let [x' (first x)]
+                  (when-let [sol (reduce (fn [_ kv]
+                                           (when-let [binds (garner-unifiers uv-fn variable? x' kv binds)]
+                                             (when-let [binds (garner-unifiers-map
+                                                                uv-fn variable?
+                                                                (dissoc x (key x'))
+                                                                (dissoc y (key kv))
+                                                                binds)]
+                                               (reduced binds))))
+                                         nil
+                                         y)]
+                    sol)))]
+        (solve (apply dissoc x concrete-ks)
+               (apply dissoc y concrete-ks)
+               simple-binds)))))
+
 (defn- garner-unifiers
   &quot;Attempt to unify x and y with the given bindings (if any). Potentially returns a map of the 
    unifiers (bindings) found.  Will throw an `IllegalStateException` if the expressions
@@ -117,6 +147,8 @@
       (variable? y)             (uv-fn variable? y x binds)
       (wildcard? x)             (uv-fn variable? (second x) (seq y) binds)
       (wildcard? y)             (uv-fn variable? (second y) (seq x) binds)
+      (and (map? x) (map? y))   (when (= (count x) (count y))
+                                 (garner-unifiers-map uv-fn variable? x y binds))
       (every? composite? [x y]) (garner-unifiers uv-fn
                                                  variable?
                                                  (rest x) 
diff --git a/src/test/clojure/clojure/core/unify_test.clj b/src/test/clojure/clojure/core/unify_test.clj
index a96d476..57a27da 100644
--- a/src/test/clojure/clojure/core/unify_test.clj
+++ b/src/test/clojure/clojure/core/unify_test.clj
@@ -100,3 +100,28 @@
     (is (= {} (unify '[1 ?x] '[1])))
     (is (= {} (unify '[1 ?x ?y ?z] '[1])))))
 
+
+(deftest map-order
+  (testing &quot;Map unification is not sensitive to array map order&quot;
+    (is (= '{?a 1, ?b 2} (unify '{:a ?a :b ?b} {:a 1 :b 2})))
+    (is (= '{?a 1, ?b 2} (unify '{:a ?a :b ?b} {:b 2 :a 1})))
+    (testing &quot;including when keys are unified&quot;
+      (is (= '{?a 1, ?b :b} (unify '{:a ?a ?b :b} {:a 1 :b :b})))
+      (is (= '{?a 1, ?b :b} (unify '{:a ?a ?b :b} {:b :b :a 1})))))
+  (testing &quot;handles collisions in keys&quot;
+    (let [kws #{:a :b :c :d :e :f :g :h :i :dCv :wxW}]
+      (is (= '{?a 1} (unify (zipmap kws (repeat '?a))
+                            (zipmap kws (repeat 1)))))
+      (is (= '{?a 1} (unify (zipmap (reverse kws) (repeat '?a))
+                            (zipmap kws (repeat 1)))))))
+  (testing &quot;Backtracks on complex keys&quot;
+    (is (= '{?a 1, ?b 2, ?c 3, ?d 3, ?e 4}
+           (unify '{?a [?b ?c]
+                    ?d [?e ?e]}
+                  {1 [2 3]
+                   3 [4 4]})))
+    (is (= '{?a 1, ?b 2, ?c 3, ?d 3, ?e 4}
+           (unify '{?a [?b ?c]
+                    ?d [?e ?e]}
+                  {3 [4 4]
+                   1 [2 3]})))))
&lt;/code&gt;&lt;/pre&gt;
</description>
<category>core.unify</category>
<guid isPermaLink="true">https://ask.clojure.org/index.php/14147/core-unify-doesnt-handle-maps-correctly?show=14153#a14153</guid>
<pubDate>Sun, 29 Sep 2024 21:02:56 +0000</pubDate>
</item>
<item>
<title>Answered: core.unify run-tests.sh file has an error</title>
<link>https://ask.clojure.org/index.php/14145/core-unify-run-tests-sh-file-has-an-error?show=14146#a14146</link>
<description>&lt;p&gt;Fixed. Thanks for the heads up. I used 1.11.4 and updated &lt;code&gt;:1.10&lt;/code&gt; to 1.10.3.&lt;/p&gt;
</description>
<category>core.unify</category>
<guid isPermaLink="true">https://ask.clojure.org/index.php/14145/core-unify-run-tests-sh-file-has-an-error?show=14146#a14146</guid>
<pubDate>Sat, 28 Sep 2024 17:11:54 +0000</pubDate>
</item>
<item>
<title>Answered: Dead code in occurs? function</title>
<link>https://ask.clojure.org/index.php/8135/dead-code-in-occurs-function?show=8141#a8141</link>
<description>Reference: &lt;a href=&quot;https://clojure.atlassian.net/browse/UNIFY-7&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;https://clojure.atlassian.net/browse/UNIFY-7&lt;/a&gt; (reported by glchapman)</description>
<category>core.unify</category>
<guid isPermaLink="true">https://ask.clojure.org/index.php/8135/dead-code-in-occurs-function?show=8141#a8141</guid>
<pubDate>Wed, 26 Jun 2019 12:00:00 +0000</pubDate>
</item>
<item>
<title>Answered: Create tests for k&amp;v map unification</title>
<link>https://ask.clojure.org/index.php/8134/create-tests-for-kv-map-unification?show=8140#a8140</link>
<description>Reference: &lt;a href=&quot;https://clojure.atlassian.net/browse/UNIFY-6&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;https://clojure.atlassian.net/browse/UNIFY-6&lt;/a&gt; (reported by fogus)</description>
<category>core.unify</category>
<guid isPermaLink="true">https://ask.clojure.org/index.php/8134/create-tests-for-kv-map-unification?show=8140#a8140</guid>
<pubDate>Wed, 26 Jun 2019 12:00:00 +0000</pubDate>
</item>
<item>
<title>Answered: Between clojure 1.6 and clojure 1.7, unification of maps stopped working correctly</title>
<link>https://ask.clojure.org/index.php/8133/between-clojure-clojure-unification-stopped-working-correctly?show=8138#a8138</link>
<description>Reference: &lt;a href=&quot;https://clojure.atlassian.net/browse/UNIFY-9&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;https://clojure.atlassian.net/browse/UNIFY-9&lt;/a&gt; (reported by eraserhd)</description>
<category>core.unify</category>
<guid isPermaLink="true">https://ask.clojure.org/index.php/8133/between-clojure-clojure-unification-stopped-working-correctly?show=8138#a8138</guid>
<pubDate>Wed, 26 Jun 2019 12:00:00 +0000</pubDate>
</item>
<item>
<title>Answered: Enhance documentation</title>
<link>https://ask.clojure.org/index.php/8132/enhance-documentation?show=8137#a8137</link>
<description>Reference: &lt;a href=&quot;https://clojure.atlassian.net/browse/UNIFY-3&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;https://clojure.atlassian.net/browse/UNIFY-3&lt;/a&gt; (reported by fogus)</description>
<category>core.unify</category>
<guid isPermaLink="true">https://ask.clojure.org/index.php/8132/enhance-documentation?show=8137#a8137</guid>
<pubDate>Wed, 26 Jun 2019 12:00:00 +0000</pubDate>
</item>
<item>
<title>Answered: Handle sets correctly</title>
<link>https://ask.clojure.org/index.php/8131/handle-sets-correctly?show=8136#a8136</link>
<description>Reference: &lt;a href=&quot;https://clojure.atlassian.net/browse/UNIFY-8&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;https://clojure.atlassian.net/browse/UNIFY-8&lt;/a&gt; (reported by alex+import)</description>
<category>core.unify</category>
<guid isPermaLink="true">https://ask.clojure.org/index.php/8131/handle-sets-correctly?show=8136#a8136</guid>
<pubDate>Wed, 26 Jun 2019 12:00:00 +0000</pubDate>
</item>
</channel>
</rss>