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.
Related
I am trying to write a macro that will allow me to do the following
(without-nesting
(:= x 1)
(:= y 2)
(:= z 3)
(db-call x y z)
(:= p 33)
(db-call x y z p))
becomes
(let [x 1
y 2
z 3]
(db-call x y z)
(let [p 33]
(db-call x y z p)))
So far my implementation has been the following
(defn assignment?
[[s _]]
(= s ':=))
(defmacro without-nesting
[& body]
(let [[bindings xs] (split-with assignment? body)
[non-bindings remaining] (split-with (complement assignment?) xs)]
`(let [~#(mapcat rest bindings)]
~#non-bindings
~(when (seq remaining)
`(without-nesting ~#remaining)))))
I'm having issues when remaining is going to be empty. In my current implementation a nil gets placed which prevents the last form in non-bindings to return its value. I have no clue on how to proceed with a recursive macro. Can someone help
UPDATE:
So I was able to get rid of the nil but I just want to know if there's a better way to deal with this
(defmacro without-nesting
[& body]
(let [[bindings xs] (split-with assignment? body)
[non-bindings remaining] (split-with (complement assignment?) xs)]
`(let [~#(mapcat rest bindings)]
~#non-bindings
~#(if (seq remaining)
[`(without-nesting ~#remaining)]
[]))))
Also would this be a good way to write code? Or do you see any caveats? For me it looks more linear as compared to nested let
I do see how ppl may abuse this. In the case of let, if the nesting becomes too much, then it's a hint to refactor the code. This might hide that
Just use let. It is already recursive. To incorporate function calls where you only care about the side effects, the convention is to bind to an underscore.
(let [x 1
y 2
z 3
_ (db-call x y z)
p 33
_ (db-call x y z p)])
I'm extremely new to Clojure and very new to functional programming. I'm expecting this to return True or False but it's just infinitely recursing and it doesn't seem to be hitting true at all.
My test data set is this:
(def y (list 1 2 3 4)) ; and I'm passing in 2 for X.
(defn occursIn [x y]
(if (= y nil)
"False"
(if (= x first y )
"True"
(occursIn x (rest y))
)
)
)
Try this, and please pay attention to the recommended way to format your code - don't leave lonely parentheses on a line by themselves, they're not like {} in other programming languages:
(defn occursIn [x y]
(if (empty? y)
"False"
(if (= x (first y))
"True"
(occursIn x (rest y)))))
You forgot to call first on the y list, like this:
(first y)
Also, notice that the base case isn't working as you expected. Use this test instead:
(empty? y)
For completeness' sake, here's a more idiomatic way to write the same procedure - but beware of the edge case pointed by #omiel in the comments, this won't work if x is false or nil:
(defn occursIn [x y]
(if (some #(= x %) y)
"True"
"False"))
An even better solution, free from the edge case - as suggested by #mange in the comments:
(defn occursIn [x y]
(if (every? #(not= x %) y)
"False"
"True"))
Oscar's answer is correct and helpful, but I just thought I'd provide an alternate answer which demonstrates how to make a function which is closer to your original function, while still being relatively idiomatic clojure:
(defn occurs-in [needle haystack]
(if-let [[head & tail] (seq haystack)]
(if (= needle head)
"True"
(recur needle tail))
"False"))
In this case I've:
used destructuring to extract head/tail instead of using first/rest on a sequence.
used if-let to bind those names only if haystack is non-empty (that is, if (seq haystack) is truthy).
used recur instead of occurs-in to ensure that this function will be compiled to use tail call elimination, so it calls itself again without using an additional stack frame.
This may not be an issue for small inputs, but it's essential to make it work for calls like (occurs-in 1000000 (range))
In terms of idiomatic naming, see that I've used occurs-in instead of occursIn: generally lisps use hyphens (lisp-case) instead of camel case (camelCase) for names.
Before we do anything else, let's replace "True" with boolean true and "False" with boolean false. The reason for doing this will become apparent.
The fundamental problem is that rest never returns nil. It returns the empty list () instead. And (rest ()) is (). So you get an endless sequence of recursive calls that ultimately blow the top off the stack.
next does return nil where rest returns (). So use next instead of rest and at least we get an answer:
(def aList (list 1 2 3 4))
(defn occursIn [x y]
(if (= y nil)
false
(if (= x first y)
true
(occursIn x (next y))
)
)
)
(occursIn 2 aList)
; false
... but the wrong answer. Why? As #OscarLopez says, you are missing parentheses around first y to call first upon the argument y. As it stands,
(= x first y)
tests whether x, first, and y are all equal. There is only one way this can happen:
(occursIn first first)
; true
... not what we want. So, let's call first instead of comparing it:
(defn occursIn [x y]
(if (= y nil)
false
(if (= x (first y))
true
(occursIn x (next y))
)
)
)
(occursIn 2 aList)
; true
It works.
Actually, the base case does work:
(occursIn 2 ())
; false
... but only because the next call turns () into nil: queasy.
And it does misfire searching for nil:
(occursIn nil ())
; true
... because (first ()) returns nil and nil pretends to be () when asked to be a sequence (this is called nil punning), so (first nil) is nil.
So, again following Oscar, we had better test whether y is empty, not whether it is nil:
(defn occursIn [x y]
(if (empty? y)
false
(if (= x (first y))
true
(occursIn x (next y))
)
)
)
(occursIn nil ())
; false
The logic is now correct. Let's make it clearer by using and and or instead of ifs with explicit true and false results (a code smell, in my view):
(defn occursIn [x y]
(and (not (empty? y))
(or (= x (first y))
(occursIn x (next y))
)
)
)
The code reads easily now. It is to do this that we used the proper boolean values.
Only two more changes:
If you look up empty?, you'll find that (empty? y) means (not
(seq y)), so (not (empty? y)) means (not (not (seq y))), which is
equivalent to (seq y).
The recursive call to occursIn is the last thing that happens: it
is said to be in tail position. We can therefore replace it by
recur. This consumes no stack, so puts no limit on the length of
the sequence that can be searched.
So we end up with ...
(defn occursIn [x y]
(and (seq y)
(or (= x (first y))
(recur x (next y))
)
)
)
I understand that project in core.logic is not relational.
However, it seems that I can get relational-like behaviour by projecting in both directions inside conda, e.g.:
(defn lifto-with-inverse
"Lifts a unary function and its inverse into a core.logic relation."
([f g]
(fn [& vs]
(let [[x y] vs]
(conda
[(pred x number?) (project [x] (== y (f x)))]
[(pred y number?) (project [y] (== x (g y)))])))))
(let [inco (lifto-with-inverse inc dec)]
(run* [q] (inco q 3)))
=> 2
Does this count as a relational operation? Or is there something else missing that makes this non-relational?
It still seems like in this case one of the arguments must be ground making it non-relational.
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))
I'm trying to create a new type in Clojure using deftype to implement a two dimensional (x,y) coordinate, which implements a "Location" protocol.
I'd also like to have this implement the standard Java equals, hashCode and toString methods.
My initial attempt is:
(defprotocol Location
(get-x [p])
(get-y [p])
(add [p q]))
(deftype Point [#^Integer x #^Integer y]
Location
(get-x [p] x)
(get-y [p] y)
(add [p q]
(let [x2 (get-x q)
y2 (get-y q)]
(Point. (+ x x2) (+ y y2))))
Object
(toString [self] (str "(" x "," y ")"))
(hashCode [self] (unchecked-add x (Integer/rotateRight y 16)))
(equals [self b]
(and
(XXXinstanceofXXX Location b)
(= x (get-x b))
(= y (get-y b)))))
However the equals method still needs some way of working out if the b parameter implements the Location protocol.
What is the right approach? Am I on the right track?
To test if something satisfies a protocol, there's satisfies?.
Edit:
Protocols and datatypes are too new in Clojure (and still evolving fast) for me to remark much about what's idiomatic or not. But you should note that defrecord already implements type-and-value-based equality. Unless you really need a custom hashcode for your objects, you could consider using defrecord.
(defrecord Point [#^Integer x #^Integer y]
Location
(get-x [p] x)
(get-y [p] y)
(add [p q]
(let [x2 (get-x q)
y2 (get-y q)]
(Point. (+ x x2) (+ y y2)))))
user> (= (Point. 1 2) {:x 1 :y 2})
false
user> (= (Point. 1 2) (Point. 1 2))
true
You also get the added bonus of being able to access your fields via keyword lookup, and being able to put metadata on your objects, which defrecord gives you for free.
user> (:x (Point. 1 2))
1
It's possible that defrecord-defined things will have custom reader syntax someday in Clojure, so they can be printed readably and read back in with the Clojure reader. Unless you're really attached to your version of toString, you might keep this in mind as well. Right now, records already print human-readably if not machine-readably.
user> (Point. 1 2)
#:user.Point{:x 1, :y 2}