我想知道是否有其他人曾经需要,因此编码了一个类似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)))
但是我很难尝试编写seqo
代码,(seqo [[:foo 3]] {:foo 3})
会成功。
谢谢!
答案 0 :(得分: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})
的任何排列进行测试。例如,对于我正在使用(seq {:a 1 :b 2 :c 3}) ;=> ([:a 1] [:c 3] [:b 2])
的实现。你可以通过排列解决这个问题,但这可能不是你想要的更大的地图。