-
-
Save abp/4118735 to your computer and use it in GitHub Desktop.
Possible syntaxes for flexible unifier w/ multi-lvar constraints
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;;Support for simple constraints on lvars during unification was added in 76fd4d7c: | |
;; | |
;; https://github.com/clojure/core.logic/commit/76fd4d7c155161d74ad5cd8d87955148eece1fe0 | |
;; | |
;;but these constraints apply to a single lvar only. | |
;;The unifier could support more general constraints if it accepted an explicit predicate function. | |
;;For instance, given this `data-numeric?` predicate and `spec` data: | |
(defn data-numeric? [data dimension] | |
(number? (-> data first dimension))) | |
(def spec {:data (repeatedly 10 #(hash-map :val (rand) :cat (rand-nth [:a :b :c]))) | |
:mapping {:y :val}}) | |
;;I'd like a unifier call that has the same semantics as: | |
(run* [q] | |
(fresh [data dim] | |
(== spec {:data data :mapping {:y dim}}) | |
(project [data dim] | |
(== true (data-numeric? data dim))) | |
(== q :success))) | |
;;A concise syntax is | |
(unifier1 spec | |
'{:data ?data :mapping {:y ?dim}} | |
'(data-numeric? ?data ?dim)) | |
;;but that would require `unifier1` to | |
;; + prep all of its arguments together | |
;; + treat its third argument (or last, if more than 3 args) specially | |
;; + prep, project, and eval the predicate form, which feels gross. | |
;;We can avoid the last-argument issue via a dynamic var: | |
(binding [*unifier-constraints* '(data-numeric? ?data ?dim)] | |
(unifier2 spec)) | |
;;This maintains backwards compatibilty at the expense of being klunky (and suffers from the same prep+project+eval issue). | |
;;A more programmatically flexible syntax: | |
(unifier3 '[spec {:data ?data :mapping {:y ?dim}} | |
:where | |
[data-numeric? ?data ?dim]]) | |
;;where everything before the `:where` is something to unify and everything after is a tuple of the form [predicate & lvar-arguments]. | |
;;This syntax could be used with the existing unifier since the single-arity implementation is currently undefined. | |
;;This syntax is my preference thus far. | |
;;In any of these syntaxes, I'm not sure if we can/want to support anonymous functions, or if in that case the user should just ball up and write a full run* form. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment