I trying my hand at core.logic which has always interested me but it has a steep learning curve. The domain I am mostly interested in is constraint satisfaction problems. For example if I have the following function, how can I translate this into a core.logic function that can be used in two ways.

Given some input return true or false (same as current impl)

Return a list of all combinations that would result in the function returning true. This is the true power of core.logic.

(defn my-exp
[a b c]
(and (= a "a") (= c "c")
(or (= b "b") (not= b "r"))))

My attempts at translating this involves nested conde. The problem with that is that the return values are not what I expect.

Update:
Here is one way I find some success but it feels strange to just put the original code inside project.

(l/run* [q a b c]
(l/membero a ["a" "r"])
(l/membero b ["b" "r" "a"])
(l/membero c ["a" "c"])
(l/project [a b c]
(l/== q (and (= a "a") (= c "c")
(or (= b "b") (not= b "r"))))
))

Sorry about the quality of this query. The example is just an example showing a type of expression I would like to be able to express. What im looking for is a generic way to translate logic expressions for some set of variables containing strings. The logic expressions contain the following operators (and not or = not=). What would be the generic way to think about such a transformation?

In the example the domain is just made up. I real life the domains will be a set of strings over which there are some constraints.

My example provide 2 solutions: ([true "a" "b" "c"] [true "a" "a" "c"])

The use of project here is probably not really needed?

(l/run* [a b c]
(l/membero a ["a" "r"])
(l/membero b ["b" "r" "a"])
(l/membero c ["a" "c"])
;; implicit AND by just adding expressions:
(l/== a "a")
(l/== c "c")
(l/conde ;; "OR"
[(l/== b "b")]
[(l/!= b "r")]))

gives:

(["a" "b" "c"] ["a" "b" "c"] ["a" "a" "c"])

But this is slighly confusing, since the clause b = “b” and the clause b != “r” is counted as two different clauses (solutions) but can reach satisfaction when b has the same values in two different cases.

Using conda or condu as the OR clause seems to work, because they terminate differently than conde.

(l/run* [a b c]
(l/membero a ["a" "r"])
(l/membero b ["b" "r" "a"])
(l/membero c ["a" "c"])
(l/== a "a")
(l/== c "c")
(l/condu
[(l/== b "b")]
[(l/!= b "r")]))