我想将具有有限域的新lvar放入映射中,并在代码的另一部分中建立它们之间的关系。考虑下面的片段:
(l/run 1 [q]
(l/fresh [x y z a b c]
(fd/in x y z (fd/interval 0 100)) ; establish domain for x y z
(let [w {:a x :b y :c z}] ; store x y z in a map
(l/all
(l/featurec w {:a a :b b :c c}) ; extract x y z as a b c
(fd/+ a b c))) ; a relationship
(l/== q [a b c])))
==> Error printing return value at clojure.core.logic/verify-all-bound$verify-all-bound* (logic.clj:2136).
Constrained variable <lvar:a__5787> without domain
有办法做到这一点吗?
Featurec的设计不允许派生值(请参阅core.logic/Featurec文档中的链接示例(。
通常,以"c"结尾的core.logic函数是专门用于过滤("约束"(从以前的逻辑函数中派生的可能值的集合/域的"约束函数"。这是库作者提出的一个有用的命名约定,我也看到core.logic的用户试图坚持它。
不过,对于这个特殊的问题,正常的统一是很好的。
(l/run* [q]
(l/fresh [x y z a b c]
(fd/in x y z (fd/interval 0 3)) ; establish domain for x y z
(let [w {:a x :b y :c z}] ; store x y z in a map
(l/all
(l/== w {:a a :b b :c c}) ; extract x y z as a b c
(fd/+ a b c))) ; a relationship
(l/== q [a b c])))
=> ([0 0 0] [1 0 1] [0 1 1] [0 2 2] [2 0 2] [1 1 2])
或者,如果你只想要某些值,只需提取lvar并单独统一即可:
(l/run* [q]
(l/fresh [x y z a b c]
(fd/in x y z (fd/interval 0 2)) ; establish domain for x y z
(let [w {:a x :b y :c z}] ; store x y z in a map
(l/all
(l/== a (w :a)) (l/== b (w :b)) ; extract x y z as a b c
(fd/+ a b c))) ; a relationship
(l/== q [a b c]) ))
=> ([0 0 0] [1 0 1] [0 1 1] [0 2 2] [2 0 2] [1 1 2] [1 2 3] [2 1 3] [2 2 4])
(还要注意,我们没有统一c和z,所以c可以在区间之外(
如果你愿意,你可以列出你想要的lvar和相应的密钥,然后使用everyg为每对添加一个关系:
(l/run* [q]
(l/fresh [x y z a b c]
(fd/in x y z (fd/interval 0 2)) ; establish domain for x y z
(let [w {:a x :b y :c z}
targlist [a b c]
wantedlist [:a :b :c]] ; store x y z in a map
(l/all
(everyg #(l/==
(get targlist %)
(w (get wantedlist %)))
(range (count targlist))) ; extract x y z as a b c
(apply fd/+ [a b c]))) ; a relationship
(l/== q [a b c])))
=> ([0 0 0] [1 0 1] [0 1 1] [0 2 2] [2 0 2] [1 1 2])