Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Extracting elements of a map from Clojure core.logic

I am trying to pull data out of a map using Clojure core.logic. This code does as I want it to:

 (run 10 [q] 
   (fresh [?id ?type ?name] 
      (membero ?type [:t2 :t1])
      (== q [?id ?name])
      (membero {:id ?id :type ?type :name ?name}  
           [
           {:id 1 :type :t1 :name "one"}
           {:id 2 :type :t2 :name "two"}
           ])))
=> ([2 "two"] [1 "one"])

However if I add some other elements to the map then it fails to match:

(run 10 [q] 
   (fresh [?id ?type ?name] 
      (membero ?type [:t2 :t1])
      (== q [?id ?name])
      (membero {:id ?id :type ?type :name ?name}  
           [
           {:id 1 :type :t1 :name "one" :other1 :o1}
           {:id 2 :type :t2 :name "two" :other2 :o2}
           ])))

I understand why matcho is not working as the maps no longer the same. My quesiton is, how can I change this so that it works again? How do I get it to match on only some of the keys in a map or how can I get it to match whatever random keys a map may have?

EDIT:

I got it to work using patial-map (thanks to https://github.com/clojure/core.logic/pull/10)

(run 10 [q] 
   (fresh [?id ?type ?name] 
          (membero ?type [:t2 :t1])
          (== q [?id ?name])
          (membero (partial-map {:id ?id :type ?type :name ?name} )
                   [
                    {:id 1 :type :t1 :name "one" :other1 :o2}
                    {:id 2 :type :t2 :name "two" :other2 :o1}
                    ])))

However I found a note that featurec should be used instead of partial-map. My new question: How to change this to use featurec?

like image 360
M Smith Avatar asked Jan 04 '13 16:01

M Smith


1 Answers

Answering my own question:

Here is the working code:

(run 10 [q] 
   (fresh [?id ?type ?name ?pm] 
          (membero ?type [:t2 :t1])
          (== q [?id ?name])
          (featurec ?pm  {:id ?id :type ?type :name ?name} )
          (membero ?pm
                   [
                    {:id 1 :type :t1 :name "one" :other1 :o2}
                    {:id 2 :type :t2 :name "two" :other2 :o1 :another :ao2}
                    {:id 3 :type :t3 :name "three" :other2 :o1 :another :ao1}
                    ]))))

This code allows me to extract values from a map but only paying attention to the keys that are really important. The rest of the key value pairs are ignored.

like image 181
M Smith Avatar answered Nov 15 '22 08:11

M Smith