I want to put fresh lvars with a finite domain into a map, and establish a relationship between them in another part of my code. Consider the snippet below:
(l/run 1 [q]
(l/fresh [x y z a b c]
(fd/in x y z (fd/interval 0 100)) ; establish domain for x y z
(let [w {:a x :b y :c z}] ; store x y z in a map
(l/all
(l/featurec w {:a a :b b :c c}) ; extract x y z as a b c
(fd/+ a b c))) ; a relationship
(l/== q [a b c])))
==> Error printing return value at clojure.core.logic/verify-all-bound$verify-all-bound* (logic.clj:2136).
Constrained variable <lvar:a__5787> without domain
Is there a way to accomplish this?
Featurec isn't designed to allow deriving values (see link's example in the core.logic/featurec documentation).
In general, you can expect core.logic functions that end with a 'c' to be 'constraint functions' specialized towards filtering ('constraining') a set/domain of possible values already derived from previous logic functions. It's a useful naming convention from the library authors, and from what I've seen users of core.logic try to stick to it as well.
Normal unification works fine for this particular problem, though.
(l/run* [q]
(l/fresh [x y z a b c]
(fd/in x y z (fd/interval 0 3)) ; establish domain for x y z
(let [w {:a x :b y :c z}] ; store x y z in a map
(l/all
(l/== w {:a a :b b :c c}) ; extract x y z as a b c
(fd/+ a b c))) ; a relationship
(l/== q [a b c])))
=> ([0 0 0] [1 0 1] [0 1 1] [0 2 2] [2 0 2] [1 1 2])
Or, if you only want certain values, just extract the lvars and unify individually:
(l/run* [q]
(l/fresh [x y z a b c]
(fd/in x y z (fd/interval 0 2)) ; establish domain for x y z
(let [w {:a x :b y :c z}] ; store x y z in a map
(l/all
(l/== a (w :a)) (l/== b (w :b)) ; extract x y z as a b c
(fd/+ a b c))) ; a relationship
(l/== q [a b c]) ))
=> ([0 0 0] [1 0 1] [0 1 1] [0 2 2] [2 0 2] [1 1 2] [1 2 3] [2 1 3] [2 2 4])
(also note that we didn't unify c and z, so c can be outside the interval)
If you want, you can make a list of the lvars and corresponding keys you want, and then use everyg to add a relation for each pair:
(l/run* [q]
(l/fresh [x y z a b c]
(fd/in x y z (fd/interval 0 2)) ; establish domain for x y z
(let [w {:a x :b y :c z}
targlist [a b c]
wantedlist [:a :b :c]] ; store x y z in a map
(l/all
(everyg #(l/==
(get targlist %)
(w (get wantedlist %)))
(range (count targlist))) ; extract x y z as a b c
(apply fd/+ [a b c]))) ; a relationship
(l/== q [a b c])))
=> ([0 0 0] [1 0 1] [0 1 1] [0 2 2] [2 0 2] [1 1 2])
Related
I'm trying to rewrite the below piece of core.logic code.
(run* [x y]
(fd/in x (fd/domain 1 2))
(fd/in y (fd/domain 1 2)))
o/p,
([1 1] [2 1] [1 2] [2 2])
I tried the below versions but none of them works,
(run* [x y]
(fresh [dom (fd/domain 1 2)])
(fd/in x dom)
(fd/in y dom)))
;; Error Unsupported binding form: (fd/domain 1 2)
(run* [x y]
(fresh [dom]
(== dom (fd/domain 1 2))
(fd/in x dom)
(fd/in y dom)))
O/P:
([1 1])
(run* [x y]
(let [dom (fd/domain 1 2)]
(fd/in x dom)
(fd/in y dom)))
O/P:
([_0 1] [_0 2])
What's the rationale for the 3 versions that I tried? Any help would be greatly appreciated.
fd/domain returns a concrete value that can be used with other goals/relations in the fd namespace — you can define it once and use it inside run* more than once:
(let [dom (fd/domain 1 2)]
(run* [x y]
(fd/in x dom)
(fd/in y dom)))
=> ([1 1] [2 1] [1 2] [2 2])
What's the rationale for the 3 versions that I tried?
The first refactoring doesn't work because fresh is being used like let, but it doesn't work like that; fresh simply allows you to give names to some fresh logic variables.
The second refactoring doesn't work because the domain value is being bound to a logic variable, and fd/in wants a concrete domain value as its second argument — not a (fresh) logic variable.
The third refactoring doesn't work (I assume) because let bindings aren't going to work like that inside the run* macro, which only wants a sequence of goals in its body.
So in ES6, I can do something like this:
let x=1 y=1 z=1
let o = {x, y,z}
console.log(o.x) //prints 1
I don't see any built in way to do something like this in clojure. Can one do any better than this to return a map from a function that takes a number of arguments?
(defn foo
[x y z]
{:x x :y y :z z})
(pprint (get ( foo 1 2 3) :x)) ;prints 1
There's a dozen reasons why doing this isn't a good idea, but the cool thing about a lisp is that you can do what you want, and if the language doesn't do what you want, you can extend it.
Here's a simple macro
(defmacro infer-map [& args]
{:pre [(every? symbol? args)]}
`(hash-map
~#(interleave
(map (comp keyword name) args)
args)))
And the usage:
(let [x 1 y 2 z 3]
(infer-map x y z))
=> {:y 2, :z 3, :x 1}
You can do this using vals->context and with-context in the Tupelo Clojure library. The unit tests show this feature in action:
(dotest
(let [ctx (let [a 1
b 2
c 3
d 4
e 5]
(vals->context a b c d e)) ]
(is= ctx {:a 1 :b 2 :c 3 :d 4 :e 5})
(let [{:keys [a b c d e]} ctx]
(is= [a b c d e] [1 2 3 4 5]))
(with-context ctx [a b c d e]
(is= [a b c d e] [1 2 3 4 5])
(is= 15 (+ a b c d e)))
(with-context ctx [b a d c e] ; order doesn't matter
(is= [a b c d e] [1 2 3 4 5])
(is= 15 (+ a b c d e)))
(throws?
(with-context ctx [x y z]
(println "shouldn't ever get here")))))
I'm a beginner with logic programming.
I'm trying to implement a sorting relation like this:
(sorto [3 2 1][1 2 3]) -> #s
I'am using clojure and core.logic:
I don't understand why this can not terminate in most cases.
Any idea would be helpful, thank you.
(require '[clojure.core.logic :refer :all]
'[clojure.core.logic.fd :as fd])
First I define several little helpers:
A simple count relation: (counto [a b] 2) -> #s
(defne counto [list n]
([() 0])
([[fl . rl] _]
(fresh [nnxt]
(fd/- n 1 nnxt)
(counto rl nnxt))))
reduce and every? relational equivalents:
(defne reduceo [rel acc x y]
([_ _ () _] (== acc y))
([_ _ [fx . rx] _]
(fresh [nacc]
(rel acc fx nacc)
(reduceo rel nacc rx y))))
(defne everyo [g list]
([_ ()])
([_ [fl . rl]]
(g fl)
(everyo g rl)))
min relation: (mino 1 2 1) -> #s
(defn mino [x y z]
(conde
[(fd/<= x y) (== x z)]
[(fd/> x y) (== y z)]))
relation between a list and its minimum element: (mino* [1 2 3 0] 0) -> #s
(defne mino* [xs y]
([[fxs . rxs] _]
(reduceo mino fxs rxs y)))
The main relation: (sorto [2 3 1 4] [1 2 3 4]) -> #s
(defne sorto [x y]
([() ()])
([[fx . rx] [fy . ry]]
(fresh [x* c]
(counto rx c)
(counto ry c)
(mino* x fy)
(rembero fy x x*)
(sorto x* ry))))
The below runs doesn't terminate, I would like to understand why.
(run* [q]
(sorto q [1 2]))
; does not terminate
(run* [q]
(sorto [2 1] q))
; does not terminate
(run* [a b]
(everyo #(fd/in % (fd/interval 10)) a)
(everyo #(fd/in % (fd/interval 10)) b)
(sorto a b))
;neither
The high level answer is because conjunction are tried in order. Reordering them may sometimes make a program to terminate -- however in the general case there may not exist a "good" order.
Have a look at Chapter 5 in https://scholarworks.iu.edu/dspace/bitstream/handle/2022/8777/Byrd_indiana_0093A_10344.pdf
I understand the following snippet of code and its corresponding output
(let [ [x y] (map list [1 2] [3 4])] (prn x) (prn y))
(1 3)
(2 4)
nil
Now the following output confuses me:
(doseq [ [x y] (map list [1 2] [3 4])] (prn x y))
1 3
2 4
nil
I think in the above snippet x will get bound to [1 3] and y will get bound to [2 4] so the output should be"
1 2
3 4
nil
The binding is pulling out the individual elements inside the larger single element in the nesting. The map creates a list ((1 3) (2 4) so the element 1 3 is first and thus that is what the doseq outputs: this is "destructuring" and the x and y are both bound from inside a single element of the list. Thus x and y are 1 and 3, and then 2 and 4.
Note also that this is the same binding that occurs in a for and the destructuring works for all sequence types.
Let's isolate the source of your confusion.
(map list [1 2] [3 4])
evaluates to
((1 3) (2 4))
So your first example
(let [[x y] (map list [1 2] [3 4])] (prn x) (prn y))
... is equivalent to
(let [[x y] [[1 3] [2 4]]] (prn x) (prn y))
... or, printing slightly differently
(let [[x y] [[1 3] [2 4]]] (prn [x y]))
... which simplifies to
(let [z [[1 3] [2 4]]] (prn z))
... producing, as expected,
; [[1 3] [2 4]]
; nil
So far, so good.
If we boil down the confusing example,
(doseq [ [x y] (map list [1 2] [3 4])] (prn x y))
... in the same way, we get, taking the liberty of printing each z whole,
(doseq [z [[1 3] [2 4]]] (prn z))
which fairly clearly produces the observed order:
[1 3]
[2 4]
nil
The difference is that the doseq binds z to each successive vector in [[1 3] [2 4]], so we don't see an enclosing [ ... ], whereas the let binds z once to the whole thing.
I try to do something like this in core.logic
(defn count-different-elements-in-list [coll]
(count (set coll)))
this works with integers just fine
(should= 1 (count-different-elements-in-list '(1 1 1)))
(should= 2 (count-different-elements-in-list '(1 1 2)))
(should= 3 (count-different-elements-in-list '(1 3 2)))
but now I'm trying to use core.logic to solve some stuff and there it get's messy
(run* [a b c]
;;the variables get values between 1 and 3
(fd/in a b c (fd/interval 1 3))
;; in the list there should only be 2 different values
(== 2 (count-different-elements-in-list '(a b c))))
but here comes the problem, a b c don't get passed as values to the function. They get passed as variables. With three variables count-different-elements-in-list returns always 3 and core.logic doesn't find a solution (empty list).
But I'm looking for this result.
([1 1 2] [1 2 1] [2 1 1]
[1 1 3] [1 3 1] [3 1 1]
[2 2 1] [2 1 2] [1 2 2]
[2 2 3] [2 3 2] [3 2 2]
[3 3 1] [3 1 3] [1 3 3]
[3 3 2] [3 2 3] [2 3 3])
You need to core.logic/project logic vars into non-relational goals, like the normal function count-different-elements-in-list. Unfortunately, you cannot project finite domain logic vars, like a, b, and c, that are not constrained to a single value. (See: this question)
In the example you have, you can swap out the fd/in and fd/interval for a generated range and membero. This would remove the unconstrained finite domain vars, keep the range constraint for integers, and allow for projection.
(def interval (vec (range 1 4)))
(run* [a b c]
(membero a interval)
(membero b interval)
(membero c interval)
(project [a b c]
(== 2 (count-different-elements-in-list (list a b c)))))