datascript
datascript copied to clipboard
Rule cross-reference doesn’t work
I've been playing around with this a bit more, and I've discovered a similar-looking bug. Let me know if I should make another issue for it.
The following situation is the same as the previous one, except instead involving rules not being found by other rules. The following code snippets should be identical.
(d/q '[:find ?kid
:in $ %
:where (wants-and-needs? ?kid :foo)]
'[["george" :wants :foo]
["george" :needs :foo]
["sally" :wants :bar]]
'[[(wants-and-needs? ?kid ?obj) [?kid :wants ?obj] [?kid :needs ?obj]]]))
;; => #{["george"]}
(d/q '[:find ?kid
:in $ %
:where (wants-and-needs? ?kid :foo)]
'[["george" :wants :foo]
["george" :needs :foo]
["sally" :wants :bar]]
'[[(wants? ?kid ?obj) [?kid :wants ?obj]]
[(needs? ?kid ?obj) [?kid :needs ?obj]]
[(wants-and-needs? ?kid ?obj) [(wants? ?kid ?obj)] [(needs? ?kid ?obj)]]]))
;; => Execution error (ExceptionInfo) at datascript.query/filter-by-pred (query.cljc:530).
;; Unknown predicate 'wants? in [(wants? ?kid :foo)]
_Originally posted by @MyriaCore in https://github.com/tonsky/datascript/issues/311#issuecomment-519237592_
Yep, I probably should've made a new issue to begin with, sorry!
No worries, it’s literally a single button click in github. Thanks for reporting!
Hey, so I'm trying to design a rule application system to get around this issue, and I encountered the same issue, even though the rule only ever recursively calls itself, and never tries to cross-reference.
(d/q '[:find ?kid
:in $ %
:where (apply :wants-and-needs? ?kid :foo)]
'[["george" :wants :foo]
["george" :needs :foo]
["sally" :wants :bar]]
'[[(apply :wants? ?kid ?obj) [?kid :wants ?obj]]
[(apply :needs? ?kid ?obj) [?kid :needs ?obj]]
[(apply :wants-and-needs? ?kid ?obj)
[(apply :wants? ?kid ?obj)]
[(apply :needs? ?kid ?obj)]]]
;; => Execution error (ExceptionInfo) at datascript.query/filter-by-pred (query.cljc:530).
;; Unknown predicate 'apply in [(apply :wants? ?kid :foo)]
Maybe the issue is that filter-by-pred is using a one-way check to dispatch based on rule heads, instead of something like unification?
Here's my stack-trace
{:clojure.main/message
"Execution error (ExceptionInfo) at datascript.query/filter-by-pred (query.cljc:530).\nUnknown predicate 'apply in [(apply :wants? ?kid :foo)]\n",
:clojure.main/triage
{:clojure.error/class clojure.lang.ExceptionInfo,
:clojure.error/line 530,
:clojure.error/cause
"Unknown predicate 'apply in [(apply :wants? ?kid :foo)]",
:clojure.error/symbol datascript.query/filter-by-pred,
:clojure.error/source "query.cljc",
:clojure.error/phase :execution},
:clojure.main/trace
{:via
[{:type clojure.lang.ExceptionInfo,
:message "Unknown predicate 'apply in [(apply :wants? ?kid :foo)]",
:data
{:error :query/where,
:form [(apply :wants? ?kid :foo)],
:var apply},
:at
[datascript.query$filter_by_pred invokeStatic "query.cljc" 530]}],
:trace
[[datascript.query$filter_by_pred invokeStatic "query.cljc" 530]
[datascript.query$filter_by_pred invoke "query.cljc" 524]
[datascript.query$_resolve_clause invokeStatic "query.cljc" 716]
[datascript.query$_resolve_clause invoke "query.cljc" 710]
[datascript.query$_resolve_clause invokeStatic "query.cljc" 712]
[datascript.query$_resolve_clause invoke "query.cljc" 710]
[clojure.core.protocols$fn__8159 invokeStatic "protocols.clj" 168]
[clojure.core.protocols$fn__8159 invoke "protocols.clj" 124]
[clojure.core.protocols$fn__8114$G__8109__8123
invoke
"protocols.clj"
19]
[clojure.core.protocols$seq_reduce invokeStatic "protocols.clj" 31]
[clojure.core.protocols$fn__8146 invokeStatic "protocols.clj" 75]
[clojure.core.protocols$fn__8146 invoke "protocols.clj" 75]
[clojure.core.protocols$fn__8088$G__8083__8101
invoke
"protocols.clj"
13]
[clojure.core$reduce invokeStatic "core.clj" 6828]
[clojure.core$reduce invoke "core.clj" 6810]
[datascript.query$solve_rule$solve__27567 invoke "query.cljc" 620]
[datascript.query$solve_rule invokeStatic "query.cljc" 634]
[datascript.query$solve_rule invoke "query.cljc" 615]
[datascript.query$resolve_clause invokeStatic "query.cljc" 792]
[datascript.query$resolve_clause invoke "query.cljc" 787]
[clojure.lang.PersistentVector reduce "PersistentVector.java" 343]
[clojure.core$reduce invokeStatic "core.clj" 6827]
[clojure.core$reduce invoke "core.clj" 6810]
[datascript.query$_q invokeStatic "query.cljc" 797]
[datascript.query$_q invoke "query.cljc" 795]
[datascript.query$q invokeStatic "query.cljc" 921]
[datascript.query$q doInvoke "query.cljc" 906]
[clojure.lang.RestFn invoke "RestFn.java" 439]
[ducktools.api.birdseye$_main invokeStatic "birdseye.clj" 362]
[ducktools.api.birdseye$_main doInvoke "birdseye.clj" 341]
[clojure.lang.RestFn invoke "RestFn.java" 397]
[clojure.lang.AFn applyToHelper "AFn.java" 152]
[clojure.lang.RestFn applyTo "RestFn.java" 132]
[clojure.lang.Var applyTo "Var.java" 705]
[clojure.core$apply invokeStatic "core.clj" 665]
[clojure.main$main_opt invokeStatic "main.clj" 514]
[clojure.main$main_opt invoke "main.clj" 510]
[clojure.main$main invokeStatic "main.clj" 664]
[clojure.main$main doInvoke "main.clj" 616]
[clojure.lang.RestFn applyTo "RestFn.java" 137]
[clojure.lang.Var applyTo "Var.java" 705]
[clojure.main main "main.java" 40]],
:cause "Unknown predicate 'apply in [(apply :wants? ?kid :foo)]",
:data
{:error :query/where, :form [(apply :wants? ?kid :foo)], :var apply}}}
I’m pretty sure recursive rules have worked before. Interesting!
Hey @MyriaCore you had a typo where your rule expressions inside wants-and-needs? were wrapped in an unwanted set of square brackets, i.e.
[(wants-and-needs? ?kid ?obj) [(wants? ?kid ?obj)] [(needs? ?kid ?obj)]]
should be
[(wants-and-needs? ?kid ?obj) (wants? ?kid ?obj) (needs? ?kid ?obj)]
(similarly in your later example)
Fixing that makes it work :)
Thanks @refset!
Not every day I get to close issues without doing anything :) Feels good :)