core.logic

Unification on Struct Maps Causes Error

Details

  • Type: Defect Defect
  • Status: Closed Closed
  • Priority: Major Major
  • Resolution: Completed
  • Affects Version/s: None
  • Fix Version/s: None
  • Component/s: None
  • Labels:
    None

Description

Unless two struct maps satisfy identical?, attempting to unify on them results in an error. Consider the following:

(defstruct element :tag :attrs :content)
(def an-element (struct element :div [] "bar"))

(run* [q]
  (membero an-element (all-elements))

Results in:

java.lang.RuntimeException: Can't remove struct key
 at clojure.lang.Util.runtimeException (Util.java:156)
    clojure.lang.PersistentStructMap.without (PersistentStructMap.java:178)
    clojure.lang.RT.dissoc (RT.java:736)
    clojure.core$dissoc.invoke (core.clj:1404)
    clojure.core.logic$eval4245$fn__4246.invoke (logic.clj:1430)
    clojure.core.logic$eval2230$fn__2231$G__2221__2240.invoke (logic.clj:36)
    clojure.core.logic$eval4139$fn__4140.invoke (logic.clj:1280)
    clojure.core.logic$eval2050$fn__2051$G__2041__2060.invoke (logic.clj:18)

During unification for IPersistentMap, the two map-like arguments have the just-compared entry removed with dissoc on recursion. For struct maps, this obviously throws the above error, whereas for Clojure records it "downgrades" them to regular maps (also sub-optimal).

(Aside: I've encountered the above using Christophe Grand's Enlive library, which still uses struct maps for modeling parsed HTML/XML documents.)

Activity

Hide
David Nolen added a comment -

There is no support for unifying struct maps. Patch welcome.

Show
David Nolen added a comment - There is no support for unifying struct maps. Patch welcome.
Hide
David Nolen added a comment -

I'm considering adding a IEmptyableCollection protocol to core.logic. If you implement then we can call it when unifying maps to preserve the original type. Does this sound satisfactory?

Show
David Nolen added a comment - I'm considering adding a IEmptyableCollection protocol to core.logic. If you implement then we can call it when unifying maps to preserve the original type. Does this sound satisfactory?
Hide
Daniel Gregoire added a comment -

Per our conversation at StrangeLoop, this sounds like a nice approach, and should solve current issues both with structmaps and records.

Show
Daniel Gregoire added a comment - Per our conversation at StrangeLoop, this sounds like a nice approach, and should solve current issues both with structmaps and records.
Hide
David Nolen added a comment -

Fixed, http://github.com/clojure/core.logic/commit/a62e7f11f02ade156043d309dc94166c9ec581b8. The record issue will be resolved in a separate ticket.

Show
David Nolen added a comment - Fixed, http://github.com/clojure/core.logic/commit/a62e7f11f02ade156043d309dc94166c9ec581b8. The record issue will be resolved in a separate ticket.
Hide
David Nolen added a comment - - edited

I refined the ticket LOGIC-58 about issues around defrecord which is really an issue around reconstructing it during reification not unification specifically.

Show
David Nolen added a comment - - edited I refined the ticket LOGIC-58 about issues around defrecord which is really an issue around reconstructing it during reification not unification specifically.

People

Vote (0)
Watch (1)

Dates

  • Created:
    Updated:
    Resolved: