This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-11-08
Channels
- # announcements (42)
- # aws (2)
- # babashka (69)
- # beginners (38)
- # calva (18)
- # cider (39)
- # circleci (1)
- # clj-commons (10)
- # cljs-dev (2)
- # clojure (36)
- # clojure-australia (14)
- # clojure-europe (25)
- # clojure-gamedev (40)
- # clojure-losangeles (4)
- # clojure-nl (5)
- # clojure-sweden (1)
- # clojure-uk (5)
- # clojurescript (133)
- # core-logic (24)
- # cursive (7)
- # datalevin (4)
- # datascript (3)
- # figwheel-main (1)
- # fulcro (45)
- # honeysql (1)
- # integrant (43)
- # introduce-yourself (1)
- # jobs (4)
- # leiningen (3)
- # lsp (32)
- # nextjournal (9)
- # pathom (18)
- # polylith (21)
- # portal (65)
- # re-frame (6)
- # releases (1)
- # remote-jobs (1)
- # reveal (12)
- # rewrite-clj (1)
- # sci (84)
- # tools-deps (22)
My first core.logic program. i’m trying to have lvar
s be values in a map of known keys. This code doesn’t seem to run the membero
functions. Any help?
I only have m
at runtime, so I can’t just hardcode in 2 logic vars, m
could have 100 keys for instance.
I think the problem is in the for
..
Also, any other advice very welcome.
(def m {:a [[1 2 3]
[2 100 200]]
:b [[1 2 3]
[2 3 4]]})
(run* [q]
(let [result-map (zipmap (keys m) (repeatedly lvar))]
(for [k (keys m)
vs (get m k)]
(membero (get result-map k) vs))
(fd/distinct (vals result-map))
(== q result-map)))
; => ({:a _0, :b _1})
minikanren is an inmutable lang/framework. goals will not be evaluated as logic relations outside run*, this means the goals inside let expression have no effect, only the last goals of let is passed into run*, this means only the last goal from the let body is evaluated. additionally, functional expression will not be evaluated as relations, this means is not posible to use a (functional) for expression, you will need to re-write the for in a relational way ( Disclaimer: I'm not an expert, nor a english native speaker 😄 )
https://github.com/clojure/core.logic/blob/master/src/main/clojure/clojure/core/logic.clj#L1281 and* will come in handy to transform the seq returned by the for expresion into a goal/relation https://github.com/clojure/core.logic/blob/master/src/main/clojure/clojure/core/logic.clj#L1276 all can combine the goals inside let body into a goal something like
(def m {:a [[1 2 3]
[2 100 200]]
:b [[1 2 3]
[2 3 4]]})
(run* [q]
(let [result-map (zipmap (keys m) (repeatedly lvar))]
(all (and* (for [k (keys m)
vs (get m k)]
(membero (get result-map k) vs)))
(fd/distinct (vals result-map))
(== q result-map))))
must say this is quite hackish, there should be a relational way to express what you want(def m {:a [[1 2 3]
[2 100 200]]
:b [[1 2 3]
[2 3 4]]})
(defn member-all [var possibles]
(and* (map #(membero var %) possibles)))
(let [vars (repeatedly (count (keys m)) lvar)]
(apply zipmap
(keys m)
(run 1 [q]
(and* (map #(member-all % %2) vars (vals m)))
(fd/distinct vars)
(== q vars))))
getting better, moved out the let
and got rid of the for
:
(def m {:a [[1 2 3]
[2 100 200]]
:b [[1 2 3]
[2 3 4]]})
(defn member-all [var possibles]
(and* (map #(membero var %) possibles)))
(let [result-map (zipmap (keys m) (repeatedly lvar))]
(run* [q]
(and* (map (fn [[k vs]] (member-all (get result-map k) vs)) m))
(distincto (vals result-map))
(== q result-map)))
It can be hard to give big o measurements of logic programs, because of how abstract they can be, but membero is basically o(n) of the collection
maybe the nail doesnt fit the hammer, dont know a better way to phrase it are you planning to run the query backwards?
relational programs can calculate the inputs given an output, it's like running it backwards
It might speed things up to move distincto up(very non-relational to care about ordering, but it might prune the search tree earlier)
wow @U0NCTKEV8 went from 86s -> 8s with distincto
first. I restarted CIDER in between, so shouldn’t be any caching.
I guess the membero is basically growing the search tree exponentially everytime, only for distincto to come along and prune most of it, putting distincto first means most the branches created by membero are immediately pruned