clojureclojure-core.logic

why the following clojure core.logic expression returns no solutions? `(run* [a b] (== {:a b} {a :b}))`


Why the first expression (involving maps) doesn't yield any solutions, whereas the second one (involving vectors) does?

(run* [a b] (== {:a b} {a :b}))

;> ()

but

(run* [a b] (== [:a b] [a :b]))

;> ([:a :b])

To narrow down the problem to map unifications, here are examples illustrating different treatments of map keys and values.

(u/unify ['{:a ?b}
          '{:a :b}])  ;=> {:a :b}

(u/unify ['{?a :b}
          '{:a :b}])  ;=> nil

Solution

  • I am not an expert in the core.logic implementation, but I found what looks like the unification algorithm for maps:

    (defn unify-with-map* [u v s]
      (when (clojure.core/== (count u) (count v))
        (loop [ks (keys u) s s]
          (if (seq ks)
            (let [kf (first ks)
                  vf (get v kf ::not-found)]
              (when-not (identical? vf ::not-found)
                (if-let [s (unify s (get u kf) vf)]
                  (recur (next ks) s)
                  nil)))
            s))))
    

    It makes no effort to unify map keys. It requires the two maps be the same size, with the same keys. If that is so, it unifies the corresponding values for each key.