سؤال

I wonder if anybody else has ever needed, and thus coded, a predicate like membero but for hash-maps. I can, of course, use (seq) on a hash-map, but if it's already an LVar, it won't work.

If we call it keyvalo, it'd work like:

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

It can be defined as

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

But I having a hard time trying to code a seqo, which would succeed for (seqo [[:foo 3]] {:foo 3}).

Thanks!

هل كانت مفيدة؟

المحلول

Easiest would be to 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))))

This is non-relational, which means that while

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

will give you a list for which [:foo 1] is a member (don't try this with run*),

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

is going to throw an exception instead. But, this probably will still suffice for your purposes.

For example, we can invert a map now

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

But,

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

Note that a problem with seqo here is that the keys in the map have no order, whereas a sequence does. Therefore, for (seqo [[:a 1] [:b 2] [:c 3]] {:a 1 :b 2 :c 3}) to succeed, you would have test for any permutation of (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]), for example. You could work around this with permutations, but that's likely not what you want for larger maps.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top