从地图中提取有限域 lvars

Extracting finite domain lvars from a map

我想将具有有限域的新鲜 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 未设计为允许派生值(请参阅 link's example in the core.logic/featurec documentation)。

通常,您可以期望以 'c' 结尾的 core.logic 函数 'constraint functions' 专门用于过滤 ('constraining') set/domain可能的值已经从以前的逻辑函数中导出。这是图书馆作者的一个有用的命名约定,据我所知,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可以在区间外)

如果你愿意,你可以列出你想要的 lvars 和相应的键,然后使用 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])