1

我在 Clojure 中有以下代码(使用 core.logic):

(db-rel parent x y)
(db-rel go-to-school x y)

(def schools
  (db
    [parent 'Adam 'Ana]
    [parent 'Adam 'Andre]
    [parent 'Adam 'Alan]
    [parent 'Bernard 'Bia]
    [parent 'Bernard 'Beatrice]
    [parent 'Carl 'Carlos]
    [parent 'Carl 'Connie]

    [go-to-school 'School1 'Ana]
    [go-to-school 'School1 'Andre]
    [go-to-school 'School2 'Alan]
    [go-to-school 'School2 'Bia]
    [go-to-school 'School2 'Beatrice]
    [go-to-school 'School1 'Carlos]
    [go-to-school 'School2 'Connie]))

我想要的是找到所有孩子都上同一所学校的所有父母。所以,在上面的列表中,我的预期回报是('Bernard),因为他的两个女儿去“school2”,每个其他父母至少有一个孩子不会去其他人的同一所学校。

这对 core.logic 可行吗?如果是这样,我该怎么做?

4

1 回答 1

1

永远不要忘记,当您使用 Core.logic 时,您可以完全访问 Clojure。让我们将每个家长与一所学校联系起来,并在那里工作:

stack-prj.logic-school> (set
 (pldb/with-db schools
   (run* [par sch]
     (fresh [kid]
       (go-to-school sch kid)
       (parent par kid)))))
#{[Bernard School2] [Adam School2] [Carl School2] [Carl School1] [Adam School1]}

我使用标准的 Clojure 函数set来获得独特的结果。从那里,我们可以group-by从第一个元素中filter取出计数大于 1 的所有内容,结果将是父母将所有孩子送到一所学校(作为键,因此我们需要first从每个项目中获取元素)。

(defn parent-with-one-school []
  (->> (set
        (pldb/with-db schools
          (run* [par sch]
            (fresh [kid]
              (go-to-school sch kid)
              (parent par kid)))))
       (group-by first)
       (filter #(= 1 (count (second %))))
       (map first)))

让我们测试一下!

stack-prj.logic-school> (parent-with-one-school)
(Bernard)
于 2016-04-12T16:32:33.773 回答