1

我想知道是否有其他人曾经需要并因此编码了一个谓词,例如membero但用于哈希映射。当然,我可以(seq)在哈希映射上使用,但如果它已经是 LVar,它将无法工作。

如果我们调用它keyvalo,它的工作方式如下:

(run* [q]
    (fresh [m kv]
           (== m {:a 2 :b 3})
           (keyvalo kv m)
           (== q kv)))
=> ([:a 2] [:b 3])

它可以定义为

(defn keyvalo [kv map]
  (fresh [s]
         (seqo s map)
         (membero kv s)))

但是我很难尝试编写 a 代码seqo,这对于(seqo [[:foo 3]] {:foo 3}).

谢谢!

4

1 回答 1

1

最简单的方法是project

(run* [q] 
  (fresh [m] 
    (== m {:foo 1 :bar 2})      ; m is an LVar
      (project [m]              ; but when bound values are projected
        (membero q (seq m)))))  ; seq can be used
;=> ([:foo 1] [:bar 2])

(defn keyvalo [kv m] (project [m] (membero kv (seq m))))

这是非关系的,这意味着虽然

(run 1 [q] (membero [:foo 1] q))
;=> (([:foo 1] . _0))

会给你一个[:foo 1]成员列表(不要尝试这个run*),

(run 1 [q] (keyvalo [:foo 1] q))
;=> IllegalArgumentException Don't know how to create ISeq from: clojure.core.logic.LVar

将引发异常。但是,这可能仍然足以满足您的目的。

例如,我们现在可以反转地图

(run* [q] (== (partial-map {:foo q}) {:foo 1 :bar 2}))
;=> (1)
(run* [q] (== (partial-map {q 1}) {:foo 1 :bar 2}))
;=> ()

但,

(run* [q] (keyvalo [:foo q] {:foo 1 :bar 2}))
;=> (1)
(run* [q] (keyvalo [q 1] {:foo 1 :bar 2}))
;=> (:foo)

请注意,seqo这里的问题是映射中的键没有顺序,而序列有。因此,为了(seqo [[:a 1] [:b 2] [:c 3]] {:a 1 :b 2 :c 3})成功,您将测试(seq {:a 1 :b 2 :c 3})For the implementation I am using的任何排列(seq {:a 1 :b 2 :c 3}) ;=> ([:a 1] [:c 3] [:b 2]),例如。您可以通过排列来解决这个问题,但这可能不是您想要的大型地图。

于 2013-08-21T17:04:25.273 回答