I'm trying to do something very simple in Prolog, but for some reason it's not working and I can't figure out why. I'm using SWI.
I have a bunch of blocks, labeled a to f, and they're all stacked on top of each other, a being at the bottom and f all the way on top. Like this:
on(b, a).
on(c, b).
on(d, c).
on(e, d).
on(f, e).
above(X, Y) :- on(X, Y).
above(X, Y) :- on(X, Z), above(Z, Y).
So one block is above another block if there's some block beneath it that is on top of that block. Makes sense to me.
So now I want to define a predicate that tells me if a certain block has exactly 3 blocks beneath it. In my example that would be block d. So I started with:
exactlyThree(X) :- above(X, Y), above(Y, Z), above (Z, W), \+ above(W, _).
So X has exaclty three blocks beneath it if X is above a block Y, if Y is above a block Z, if Z is above a block W and block W is not above any block. But that's not working.
So I tried this, which is practically the same thing:
bottomBlock(X) :- \+ above(X, _).
exactlyThree(X) :- above(X, Y), above(Y, Z), above (Z, W), bottomBlock(W).
That didn't work either. As a test it tried:
?-bottomBlock(a).
true.
Makes sense, but then I tried:
?-bottomBlock(X).
false.
What's going on here? Why doesn't prolog say X=a? And why aren't my predicates doing what they're supposed to?
Starting from the bottom (hehe):
?-bottomBlock(X). false.
Why doesn't prolog say X=a?
Because it won't invent things to match a variable. You need to assert something, not just negate.
bottomBlock(X) :- on(_, X), \+ above(X, _).
exactlyThree(X) :- above(X, Y), above(Y, Z), above (Z, W), \+ above(W, _).
This should match 3 blocks or more: if X is above Y, it could be 10 blocks above. You need to use on
in order to guarantee it is exactly 3 blocks away.