Consider this blog post where the author implements palindrome relation using reverso:
(defn reverso [l r]
(conde
[(== l ()) (== r ())]
[(fresh [la ld ldr]
(conso la ld l)
(appendo ldr (list la) r)
(reverso ld ldr))]))
When I run (run* [q] (reverso q [1 2 3])), the output is ([3 2 1]). However, when I run (run* [q] (reverso [1 2 3] q)), the program does not terminate. I am able to get the correct result by explicitly requesting one result via run 1.
When experimenting, I was able to implement the same function myself using defne:
(defne conjo2 [l a la]
([[] _ [a]])
([[c . bs] _ [c . cs]] (conjo2 bs a cs)))
(defne reverso [l r]
([[] []])
([[a . ls] _]
(fresh [rs]
(conjo2 rs a r)
(reverso ls rs))))
but the same issue is present. However, if I change my custom conjo2 to core.logic/conjo, the position of the variable during non-termination changes.
Why does the program not terminate for the general query with specific locations of the query variable?
Why specifying run 1 succeeds, but as soon as run 2 the program does not terminate?
The problem is that when you give appendo a fresh variable on the left and a fresh variable for the result, it can produce arbitrarily many answers, none of which will lead to a solution for your overall reverso question. Witness the definition of appendo:
(defne appendo
"A relation where x, y, and z are proper collections,
such that z is x appended to y"
[x y z]
([() _ y])
([[a . d] _ [a . r]] (appendo d y r)))
It terminates if the x argument is empty (succeeding with y as the result); otherwise, it assumes that both x and the result z are non-empty lists and calls itself recursively. This terminates if either x or z can be proven to have a finite length, or if an index they share has a different value in the two lists. You never impose either of those constraints, so it continues searching forever.
Let's step through the execution of a simpler query, (run 2 [q] (reverso [1] q)).
We test whether l and r are both empty
They're not, so we fresh up some variables and assert that (conso la ld [1])
This succeeds, binding (== la 1) and (== ld []).
Next we assert that (appendo ldr [1] r).
This succeeds via the first clause in appendo, binding (== ldr []) and (== r [1]).
We recurse into (reverso [] []), and check whether both arguments are empty.
This succeeds, so we yield our first overall result: (== q [1]) (remember that at the outer level (== q r), so a solution for r is a solution for q).
We've been asked for more results, so we keep searching, which means rejecting the clause that just succeeded to see if alternatives might yield additional successes.
Rejecting 4.1 is a quick dead end: we have (== l []) at this point, so the conso fails.
Now we backtrack to 3.1, the empty-list clause in (appendo ldr [1] r). Rejecting this puts us in the second clause, (appendo d [1] r1), binding (== ldr [a . d]) and (== r1 [a . r]).
You can see this will never lead anywhere: the lists we're looking through are longer than the list we're trying to reverse. But before it can fail, it will make another recursive call to reverso, which will make a call to appendo, which will lengthen the lists again and make a recursive call to reverso, and so on. This is a simlar problem to that described in Goal ordering in Clojure's `core.logic`.
You can fix this by first informing the engine that you expect the two lists to be the same length. Then attempts by appendo to lengthen its input and output beyond the limit will fail. First, define same-lengtho:
(defn same-lengtho [xs ys]
(conde
[(== xs ()) (== ys ())]
[(fresh [x xs' y ys']
(conso x xs' xs)
(conso y ys' ys)
(same-lengtho xs' ys'))]))
Then insert a call to same-lengtho before you start the main search1:
(defn reverso* [l r]
(conde
[(== l ()) (== r ())]
[(fresh [la ld ldr]
(conso la ld l)
(appendo ldr (list la) r)
(reverso* ld ldr))]))
(defn reverso [l r]
(all (same-lengtho l r)
(reverso* l r)))
Defined as such, a run* query produces the correct results regardless of parameter order:
user=> (run* [q] (reverso q [1 2 3]))
((3 2 1))
user=> (run* [q] (reverso [1 2 3] q))
((3 2 1))
And just to show that we haven't accidentally done something one-directional with same-lengtho, observe that with totally fresh variables on both sides it still generates all possible lists and their reverses:
user=> (run 5 [a b] (reverso a b))
([() ()]
[(_0) (_0)]
[(_0 _1) (_1 _0)]
[(_0 _1 _2) (_2 _1 _0)]
[(_0 _1 _2 _3) (_3 _2 _1 _0)])
1 You don't technically need both (== l ()) and (== r ()) anymore: either one will suffice since you pre-guaranteed that the lists are the same length. But to me it seems semantically nicer to leave in the redundant check.
Related
I just read the primer for core.logic. It makes sense so far, but I'm not sure where to go to learn more.
Let's say I wanted to write my own constraint, sort of like the membero shown in the primer. This one is called vectoro and constrains things to be a vector.
(defn vectoro [s] ???)
(run* [q]
(conde
[(== q [1 2])]
[(== q :a)])
(vectoro q))
Now I want that to return [1 2]. How do you write vectoro? Is this documented anywhere?
There's a core.logic pred macro that makes this easy:
(run* [q]
(== q [1 2])
(pred q vector?))
=> ([1 2])
(run* [q]
(== q '(1 2))
(pred q vector?))
=> ()
Here's how you might define a vectoro function/contraint (but realize this is essentially the exact same thing pred is doing):
(defn vectoro [a]
(project [a]
(== true (vector? a))))
project is used to operate on the actual/concrete value of the logic variable (LVar). We can then use the plain old predicate vector? and require the result be true. This also works with your example program:
(run* [q]
(conde
[(== q [1 2])]
[(== q :a)])
(vectoro q))
=> ([1 2])
(run* [q]
(conde
[(== q '(1 2))]
[(== q :a)])
(vectoro q))
=> ()
To continue learning, I suggest looking for projects that use core.logic and seeing if their source code teaches you anything.
As for your specific question about vectoro, the "project" function (as in "projection") will probably accomplish what you want, something along the lines of
(defn vectoro [s v]
(core.logic/project [v]
(core.logic/== s (vector? v)))
I'm toying around with core.logic and trying to translate some Prolog code and run into an endless recursion for the insert facts (taken from R.A.O'Keefe's "Craft of Prolog"):
insert(L, X, [X|L]).
insert([H|T], X, [H|L]) :-
insert(T,X,L).
This is what I've come up so far (please note that the first two arguments are exchanged to match up with conso parameter list):
(defn insert [x l nl]
(conde
[(conso x l nl)]
[(fresh [h t]
(conso h t l)
(insert x t l)
(conso h l nl))]))
The problem I have is that the last two facts from these midje tests will never return.
The first one works just fine as is expected since this only requires the first conso clause.
(fact "Inserting works"
(run* [q] (insert 1 [2] q)) => '((1 2)))
(run* [q] (insert 1 [2 3] q)) => '((1 2 3)))
(fact "We can retrieve the inserted data"
(run* [q] (insert q [2] '(1 2))) => '(1))
(fact "We can retrieve the list data, too"
(run* [q] (insert 1 q '(1 2))) => '((2))))
I guess I'm overlooking something obvious, but what?
Edit: The facts don't reflect the behavior of the Prolog code correctly. The right behavior is like this:
?- insert([2,3], 1, Q).
Q = [1, 2, 3] ;
Q = [2, 1, 3] ;
Q = [2, 3, 1].
So, the second checkable should actually be
(fact "Inserting works"
(run* [q] (insert 1 [2 3] q)) => '((1 2 3) (2 1 3) (2 3 1)))
The solution is to make the recursive insert clause last:
(defn insert [x l nl]
(conde
[(conso x l nl)]
[(fresh [h t]
(conso h t l)
(conso h l nl)
(insert x t l))]))
The Prolog code can be transcribed almost verbatim as core.logic also supports matching.
(defne inserto [L, X, L*]
([L, X, (X . L)])
([(H . T), X, (H . L)] (inserto T, X, L)))
Note that I've kept the order of the Prolog version, rather than the inverted order of the first two logical variables in your version.
user=> (run* [q] (inserto [2] 1 q))
((1 2))
user=> (run* [q] (inserto [2 3] 1 q))
((1 2 3))
user=> (run* [q] (inserto [2] q [1 2]))
(1)
user=> (run* [q] (inserto q 1 [1 2]))
((2))
I'm trying to implement the opposite of membero in clojure.core.logic, but it's returning two values instead of one. Otherwise, it works fine (returns nothing when the value is in the list, and something when it is not).
(defne nonmembero
"A relation where l is a collection, such that l does not contain x"
[x l]
([_ ()])
([_ [head]]
(!= x head))
([_ [head . tail]]
(!= x head)
(nonmembero x tail)))
Example runs:
user> (run* [x] (nonmembero 1 [2 3 4 5]))
(_0 _0)
user> (run* [x] (nonmembero 1 [2 3 1 4 5]))
()
You don't need the second pattern i.e the [_ [head]. This is causing a new branch in search space of core.logic engine and hence leads to the 2 output. The last pattern i.e [head . tail] is enough to handle the case where you have only one element in the list. Now your solution becomes:
(defne nonmembero
"A relation where l is a collection, such that l does not contain x"
[x l]
([_ ()])
([_ [head . tail]]
(!= x head)
(nonmembero x tail)))
Something is wrong with the code above. It finds a solution for the following
(run* [q](== q 1)(nonmembero q [1 2 3])) => (1)
The following gives the expected result
(run* [q](== q 1)(nonmembero2 q [1 2 3])) => ()
where nonmembero2 is
(defn nonmembero2
[x l]
(fresh [h t]
(conde
[(== l ())]
[(conso h t l)
(!= x h)
(nonmembero2 x t)])))
I've started learning core.logic and I'm totally lost. I am trying to write a core.logic relation which refactors an expression, renaming symbols. I want a relation that returns for a given expression, list of symbols and a list of symbols to rename those symbols:
(defn rename [exp from to]...
the expression with all the symbols in from becoming the corresponding one in to:
e.g. (rename '(defn multiply [x y] (* x y)) [x y] [a b])
returns (defn multiply [a b] (* a b))
but it needs to be aware of scope,
so (rename '(defn q [x] ((fn [x] (* x 5)) x)) [x] [a])
would return (defn q [a] ((fn [x] (* x 5)) a))
I don't know where to start solving this - any hints would be greatly appreciated!
This problem is more suitable for FP as it is just a tree traversal and replace operation, where as LP is more about specifying constrains and asking all possible solution around those constrains for a specific input. But if you really want to do this logical way, I tried something that does try to do it LP way but it doesn't handle a lot of cases and is just a starting point.
(defrel replace-with a b)
(fact replace-with 'x 'a)
(fact replace-with 'y 'b)
(defn replace [a b]
(conde
[(replace-with a b)]
[(== a b)]))
(defn replace-list [from to]
(conde
[(== from []) (== to [])]
[(fresh [f t f-rest t-rest]
(resto from f-rest)
(resto to t-rest)
(firsto from f) (firsto to t)
(conda [(replace-list f t)]
[(replace f t)])
(replace-list f-rest t-rest))]))
(first (run 1 [q]
(fresh [from]
(== from '(defn multiply [x y] (* x y)))
(replace-list from q))))
==> (defn multiply (a b) (* a b))
Two related questions in one:
Can Clojure's core.logic module perform arithmetic, logical comparison, etc, like ordinary Prolog? I am envisioning something like the following:
(defrel points person n)
(fact :bob 2)
(fact :charlie 3)
(run* [q] (fresh [x y]
(points :bob x)
(points :charlie y)
(< x y)
(== q (+ x y))))
=> (5)
In this example, neither the logical comparison (< x y) nor the attempted binding of q to (+ x y) works. I suppose that this is because I'm working with LVars, not integers at this point, and I can't make these comparisons because the symbols aren't yet bound. But it works in prolog:
points(bob, 2).
points(charlie, 3).
?- points(bob, X), points(charlie, Y), Result is X + Y.
=> Result = 5.
In a similar vein, can I somehow use Clojure functions (which return booleans or other "truthy" values) as logic predicates? In other words, to use functions to tell Minikanren which terms unify or not. Something along the lines of:
(defmagic startswithhi-o [v]
(.startsWith v "hi"))
(defrel person n)
(fact person "bob")
(fact person "hillary")
(run* [q]
(fresh [n]
(person n)
(startswithhi-o n)
(== q n)))
=> ("hillary")
If I try things like this I get errors also complaining that the LVars aren't bound. Is there a way to do this?
Lastly if anyone has read this far, I might as well ask: are there plans to incorporate probabilistic logic into core.logic, along the lines of:
http://dtai.cs.kuleuven.be/problog/ ?
I'm not holding my breath but it would be awesome!
Non-relational arithmetic is possible via project.
(run 1 [q]
(fresh [x y]
(== x 1)
(== y 2)
(project [x y]
(== q (+ x y)))))
(3)
I believe the Prolog example given is also non-relational.
The second half of your question can also be solved via project, but you must be careful that you always input a ground value.
(defn startwith [x]
(project [x]
(== true (.startsWith x "hi"))))
PS: Hold your breath for Constraint Logic Programming to come to core.logic!
I believe you have to "project" (nonrel/project) a logic variable to its binding before you can apply a function to it:
(defrel points person n)
(fact points :bob 2)
(fact points :charlie 3)
(run* [q]
(exist [x y]
(points :bob x)
(points :charlie y)
(project [x y]
(== true (< x y))
(== q (+ x y)))))
Note that exist substitutes for fresh in the original snippet and the additional argument for the fact declarations.