I am studying DCG grammars and parse trees in Prolog using Ivan Bratko's Programming for Artificial Intelligence. In a program that uses a DCG grammar to extrapolate the meaning of a sentence, I find these two predicates that, I think, represent a kind of semantic knowledge:
properName(john) --> [john].
properName(mary) --> [mary].
How should I read these predicates? I am thinking that they mean: it is true that an element of a list represented by the string "john" is a proper name and this proper name is John (same thing for Mary).
Is it my reading correct or are there some other implications?
properName(X) is just an unary rule (in the context of DCG; it is a ternary predicate in Prolog - check it out with ?- listing(properName) ). you could've called it "socks", or "jam", it's totally up to you. So the semantic knowledge about it representing proper name "john" or "mary" is nowhere to be found in the code (it uses naming as self-documenting feature, but documentation is not code).
The predicate allows for an atom john or mary to be present in the input stream, and nothing else; and demands that X unified with that atom.
You could've defined it thus:
name(X) --> [X], { member(X, [john, mary]) }.
then,
4 ?- phrase( name(X), [john,jack], Z).
X = john,
Z = [jack] ;
false.
5 ?- phrase( name(X), [jack,john], Z).
false.
8 ?- phrase( name(X), [john,mary], Z).
X = john,
Z = [mary] ;
false.
9 ?- phrase( name(X), [mary,john,jack], Z).
X = mary,
Z = [john, jack].
11 ?- phrase( name(jack), [jack,mary,john], Z).
false.
This is a trivial predicate that does not lend itself to interpretation outside of the context in which it is used.
In other words, it can only be used to demand that a proper name is used in a certain way, by a DCG rule that uses it on its right-hand side. The way you have shown it, in isolation, it means nothing more than:
'john' is a proper name, and so is 'mary'.
EDIT
I might be wrong here, but you are still abusing the English language to describe things that are best described using a formal language. Prolog is a formal language, with a defined syntax and semantics. It can be used to formally describe logical relationships, or computation. Trying to faithfully translate it into English is bound to be clumsy and unnecessary. Something as trivial as the predicate in your question turns into something that is silly, difficult to understand, and difficult to work with.
P.S. The correct spelling of the word you like so much is representation.
Related
I am currently studying for an AI exam and my final thing to revise is Prolog.
Below you can see the question I have to solve:
If possible, unify uncle(brother(W), Q) with uncle(john, mother(S))
I am completely lost as on a high level, it doesn't unify, but I guess my knowledge of Prolog is a bit outdated.
Could someone help me understand how to unify them if possible? I don't understand how I would unify functors to atoms.
Thank you!
I find that when learning syntactic unification that it works better if you first decompose the terms into abstract syntax trees then do the unification. Doing the decomposition really helps with nested list. So after decomposition you have brother(W) trying to unify with john which will fail. Once you have a failure you can skip the rest of the unification process.
While these are not abstract syntax trees, the predicates =.. and write_term help in converting complex terms to ASTs.
Using =../2
?- uncle(brother(W),Q) =.. List.
List = [uncle, brother(W), Q].
?- uncle(john,mother(S)) =.. List.
List = [uncle, john, mother(S)].
and then trying to unify the individual terms
?- brother(W) = john.
false.
For Prolog list use write_term/2 with option dotlists(true)
?- write_term([a],[dotlists(true)]).
.(a,[])
true.
?- write_term([a,b],[dotlists(true)]).
.(a,.(b,[]))
true.
?- write_term([a,B],[dotlists(true)]).
.(a,.(_15276,[]))
true.
?- write_term([a,[b]],[dotlists(true)]).
.(a,.(.(b,[]),[]))
true.
?- write_term([a,b,[c],[d,[e,[f],g]],h],[dotlists(true)]).
.(a,.(b,.(.(c,[]),.(.(d,.(.(e,.(.(f,[]),.(g,[]))),[])),.(h,[])))))
true.
In this post are some actual ASTs for learning syntactic unification.
Do to limitation of Discourse I could not get the images to line up with the actual Prolog terms as I wanted but it is better than not having them.
What does --> mean in Prolog?
Could you provide one concrete example and explain how it works?
hardmath has already explained a lot. But the more fascinating thing about DCG is, that although the -->/2 syntax suggests context free grammars, its actually more. One can also model more complex languages thanks to attributes, which are simply parameters to the non-terminals.
Here is a DCG that generates and accepts the language L = {a^n b^n c^n}. The DCG reads as follows:
:- use_module(library(clpfd)).
start(N) --> as(N), bs(N), cs(N).
as(N) --> {N #> 0, M #= N-1}, [a], as(M).
as(0) --> [].
bs(N) --> {N #> 0, M #= N-1}, [b], bs(M).
bs(0) --> [].
cs(N) --> {N #> 0, M #= N-1}, [c], cs(M).
cs(0) --> [].
The above code makes use of a so called auxiliary conditions(*), embraced by {}, this is normal code interspersed into the DCG. And to allow bidirectional use of the DCG we were using CLP(FD) instead of ordinary arithmetic. Here are some example runs in SWI-Prolog:
?- phrase(start(X),[a,a,a,b,b,b,c,c,c]).
X = 3
?- phrase(start(3),Y).
Y = [a,a,a,b,b,b,c,c,c]
But in practice DCGs are also often found because of their ability to pass around state. They allow a form of monads in Prolog. Just replace the input list and the output list with input state and output state.
Bye
(*)
An early paper promoting DCG is:
Pereira, F.C.N. and Warren, D.H.D. (1980):
Definite Clause Grammars for Language Analysis –
A Survey of the Formalism and a Comparison with
Augmented Transition Networks, North-Holland
Publishing Company, Artificial Intelligence, 13, 231 – 278
http://cgi.di.uoa.gr/~takis/pereira-warren.pdf
The symbol --> is used in many Prolog implementations to create Declarative Clause Grammar (DCG) rules, which take the form:
head --> body.
as analogous to normal Prolog rules:
head :- body.
In fact every DCG rule can be translated into a normal Prolog rule (and is, internally), but the DCG syntax serves as a convenient and very powerful shorthand for creating rules that relate lists to a variety of Prolog structures. Often DCG rules are used for a fairly limited purpose of parsing lists.
The Question posed here is to give a simple example of the use of -->, in other words showing how DCG rules work in a simple case. The head of a DCG rule is effectively a predicate of an underlying Prolog rule with two extra arguments that represent a difference list, namely one list represented as a longer list minus some trailing portion of that longer list.
Here's a DCG example taken from the SWI-Prolog DCG tutorial adapted by Ann Ogborn from the tutorial by Markus Triska given in Boris's Comment:
as --> [ ]. % empty list is okay
as --> [a], as. % list [a|T] is okay iff T is okay
To distinguish this from a normal Prolog predicate we denote this as//0, but it is equivalent to a normal Prolog predicate with two additional arguments. We can query the underlying Prolog predicate directly by supplying the two additional arguments:
?- as([ ],[ ]).
true
This succeeds because the difference between the two lists (which is again an empty list) is okay according to as//0. Also:
?- as([a],[ ]).
true
succeeds because the difference between the two lists is [a], which is okay by recursion with as//0.
Another way to use as//0 is with the built-in Prolog predicate phrase/2, which takes as a first argument a DCG head and as a second argument a list. In this case phrase/2 will generate lists that satisfy as//0:
?- phrase(as, Ls).
Ls = '[]' ;
Ls = [a] ;
Ls = [a, a] ;
Ls = [a, a, a] ;
and so on, until you terminate the query successfully by hitting return.
This example also works with Amzi! Prolog with only minor differences in output.
So I just started Prolog and I was wondering two things:
1) Is there built in functions (or are they all called predicates?) for simple things like max of 2 numbers, or sine of a number, etc... If so, how do I access them?
2) How can I call a predicate from another one? I wrote two predicates called car and cdr. car returns the head of a list and cdr returns the list without the head. But now I want to call car on the cdr. Here are some examples for clarification:
car([3,4,5,5], H). would return H = 3
cdr([3,4,5,5],L). would return L = [4,5,5]
and what I am asking is how can I do this:
car(cdr[3,4,5,5]))
??
As others have pointed out, the predicates in Prolog are called that for a reason: they really aren't functions. Many newcomers to Prolog start out by trying to map the functionality they know in other languages over to Prolog and it generally fails. Prolog is a very different programming tool than most other languages. So it's a bit like using a variety of hammers for a long time, then having someone hand you a wrench, and you wonder why it doesn't make a good hammer.
In Prolog, predicates are a means of declaring relations between entities. If you say foo(a, b) it means there's a relationship between a and b called foo. You've probably seen the examples: knows(joe, jim). and knows(jim, sally). And you can define a relation, like:
remotely_acquainted(X, Y) :- knows(X, Z), knows(Z, Y), \+ knows(X, Y).
Or something like that.
A predicate does not return a value. It either succeeds or it fails. If you have a sequence of predicates separated by commas (an "and" relationship) and Prolog encounters a predicate that fails, it backs up (backtracks) to the nearest prior predicate which it can make succeed again with different instantiation of its arguments and moves forward again.
Just to add a little to the confusion, there are some predicates in Prolog designed specifically for the evaluation of arithmetic expressions. These act like functions, but they are special case. For example:
X is Y / gcd(Z, 4).
Here, gcd of Z and 4 is computed an its value returned, and then Y is divided by that value and the result is instantiated into X. There are a variety of other functions as well, such as max/2, sin/1, etc. You can look them up in the documentation.
Arithmetic comparative operators function this way as well (using =:=/2, >/2, </2, etc with numeric expressions). So if you say:
X < Y + Z
The Prolog will consider numerical evaluation of these arguments and then compare them.
So having said all that, Prolog does allow embedding of term structures. You could have something like:
car(cdr([1,2,3]))
as a term. Prolog will not interpret it. Interpretation is left up to the programmer. I could then create a predicate which defines an evaluation of such terms:
car([H|_], H).
cdr([_|T], T).
proc_list(car(X), Result) :-
proc_list(X, R1),
car(R1, Result), !.
proc_list(cdr(X), Result) :-
proc_list(X, R1),
cdr(R1, Result), !.
proc_list(X, X).
The cut in the above clauses prevents backtracking to proc_list(X, X) when I don't want it.
Then:
| ?- proc_list(car(cdr([1,2,3])), R).
R = 2
yes
| ?- proc_list(car(cdr(cdr([1,2,3]))), R).
R = 3
yes
| ?-
Note this is a simple case and I may not have captured all of the subtleties of doing a proper sequence of car and cdr. It can also be made more general using =.. and call, etc, instead of discrete terms car and cdr in the parameters. For example, a slightly more general proc_list might be:
proc_list(Term, Result) :-
Term =.. [Proc, X], % Assumes terms have just one argument
member(Proc, [car, cdr]), % True only on recognized terms
proc_list(X, R1), % Recursively process embedded term
ProcCall =.. [Proc, R1, Result], % Construct a calling term with Result
call(ProcCall), !.
proc_list(X, X).
This technique of processing a term does step away from relational behavior which Prolog is best at, and leans into functional behavior, but with an understand of how Prolog works.
Prolog has a really different attitude to computing...
You don't define functions, but relations among arguments. The most similar and well known language I'm aware of is SQL. Think of predicates as tables (or stored procedures, when some computation not predefined by database engine is required).
car([H|_],H).
cdr([_|T],T).
car_of_cdr(L, Car) :- cdr(L, Cdr), car(Cdr, Car).
but since lists' syntax is a core part of the language, a better definition could be
car_of_cdr([_,X|_], X).
Anyway, I think you should spend some time on some Prolog tutorial. SO info page has much more information...
:- use_module(support).
This means the module will use predicates written in other modules.
<module_name>:<predicate_name>(<atoms / Variables>).
This way you can call a predicate in another module.
Say I have the following theory:
a(X) :- \+ b(X).
b(X) :- \+ c(X).
c(a).
It simply says true, which is of course correct, a(X) is true because there is no b(X) (with negation as finite failure). Since there is only a b(X) if there is no c(X) and we have c(a), one can state this is true. I was wondering however why Prolog does not provide the answer X = a? Say for instance I introduce some semantics:
noOrphan(X) :- \+ orphan(X).
orphan(X) :- \+ parent(_,X).
parent(david,michael).
Of course if I query noOrphan(michael), this will result in true and noOrphan(david) in false (since I didn't define a parent for david)., but I was wondering why there is no proactive way of detecting which persons (michael, david,...) belong to the noOrphan/1 relation?
This probably is a result of the backtracking mechanism of Prolog, but Prolog could maintain a state which validates if one is searching in the positive way (0,2,4,...) negations deep, or the negative way (1,3,5,...) negations deep.
Let's start with something simpler. Say \+ X = Y. Here, the negated goal is a predefined built-in predicate. So things are even clearer: X and Y should be different. However, \+ X = Y fails, because X = Y succeeds. So no trace is left under which precise condition the goal failed.
Thus, \+ \+ X = Y does produce an empty answer, and not the expected X = Y. See this answer for more.
Given that such simple queries already show problems, you cannot expect too much of user defined goals such as yours.
In the general case, you would have to first reconsider what you actually mean by negation. The answer is much more complex than it seems at first glance. Think of the program p :- \+ p. should p succeed or fail? Should p be true or not? There are actually two models here which no longer fits into Prolog's view of going with the minimal model. Considerations as these opened new branches to Logic Programming like Answer Set Programming (ASP).
But let's stick to Prolog. Negation can only be used in very restricted contexts, such as when the goal is sufficiently instantiated and the definition is stratified. Unfortunately, there are no generally accepted criteria for the safe execution of a negated goal. We could wait until the goal is variable free (ground), but this means quite often that we have to wait way too long - in jargon: the negated goal flounders.
So effectively, general negation does not go very well together with pure Prolog programs. The heart of Prolog really is the pure, monotonic subset of the language. Within the constraint part of Prolog (or its respective extensions) negation might work quite well, though.
I might be misunderstanding the question, and I don't understand the last paragraph.
Anyway, there is a perfectly valid way of detecting which people are not orphans. In your example, you have forgotten to tell the computer something that you know, namely:
person(michael).
person(david).
% and a few more
person(anna).
person(emilia).
not_orphan(X) :- \+ orphan(X).
orphan(X) :- person(X), \+ parent(_, X).
parent(david, michael).
parent(anna, david).
?- orphan(X).
X = anna ;
X = emilia.
?- not_orphan(X).
X = michael ;
X = david ;
false.
I don't know how exactly you want to define an "orphan", as this definition is definitely a bit weird, but that's not the point.
In conclusion: you can't expect Prolog to know that michael and david and all others are people unless you state it explicitly. You also need to state explicitly that orphan or not_orphan are relationships that only apply to people. The world you are modeling could also have:
furniture(red_sofa).
furniture(kitchen_table).
abstract_concept(love).
emotion(disbelief).
and you need a way of leaving those out of your family affairs.
I hope that helps.
I have a little question about the negation as failure in Prolog language:
This is a question more theoretical than practical because I have clear how this example work.
so I have the following Prolog program:
/* Fatti che specificano quali esseri sono degli animali: */
animal(cat).
animal(dog).
animal(frog).
animal(horse).
animal(viper).
animal(boa).
animal(python).
/* Fatti che specificano quali esseri sono dei serpenti: */
snake(viper).
snake(boa).
snake(python).
/* X è un serpente, fallisce ed impedisce il backtracking quindi
il predicato likes(mary,X) risulta essere falso: */
likes(mary,X) :- snake(X),
!,
fail.
/* Se X è un animale allora a mary piace: */
likes(mary, X) :- animal(X).
In Prolog I can't simply say something like: "Mary loves every animals, BUT NOT THE SNAKES"
and I have to formulate it in this way: "If X is a snake, then Mary don't love it. Otherwise, if X it is an animal, mary love it"
The precedent program do exactly this thing, by the rule:
likes(mary,X) :- snake(X),
!,
fail.
Prolog check if it is true that X it is a snake, imposes the cut to avoid backtracking and force a failure of the predicate.
In this way if snake(X) is TRUE the program force the failure also of the head prediate likes(mary,X) and imposing backtracking avoid the possibility to execute the other rule in the program (that answer true because a snake is also an animal)
My question is: it seems me that this use of Prolog falls outside from the logical and declarative paradigm and in some way fall in some sort of procedural paradigm
Because:
I have to impose an order of the 2 predicate (so in some way I am saying: if the first fail, try the second).
But even more I am saying that: if the first rule match (X it is a snake) then execute a forced failure and imposes no backtracking.
This seems to me more near to a procedural meaning that a classical logical meaning...
Is it that? Is it that in these cases, Prolog uses a procedural behavior to overcome a limitation of the logic?
I disagree with 'limitations of the logic'.
The same would be
likes(mary,X) :- not(snake(X)) , animal(X).
Because Prolog uses a depth-first-search some things can be expressed in an shorter way that then depends on the depth-first-search backtracking algorithm.
x :- a, !, b.
x :- c.
x :- d.
is the same as
x :- a, b.
x :- not(a), c.
x :- not(a), d.
Programs that make use of cut (!) are most of the time
sensitive to the ordering of goals and clauses in their
meaning and not only in their termination, so they are
often not declarative.
The negation as failure (\+) ecapsulates in a certain way
the cut. It is defined and even implemented by most Prolog
systems as follows:
\+ X :- X, !, fail.
\+ _ .
Although it hints a logical meaning and thus declarativity,
the negation as failure is still sensitive to ordering of
goals. Here is an example. Assume we have the following
database:
p(a).
q(b,c).
Then the following query produces X=a as a solution:
?- p(X), \+ q(X,Y).
X = a.
But if the arguments of the conjunction (,)/2 switch side,
a different result is obtained:
?- \+ q(X,Y), p(X).
false.
Ergo, negation as failure is not declarative per se. For
ground term flow of arguments, negation as failure sneeks
in an existential quantifiers. So a query of the form:
?- A(X), \+ B(X,Y).
Has essentially the meaning that it quantifies the fresh
variables Y inside the negation:
?- A(X), ~ exists Y B(X,Y).
So in the above example where conjunction is switched, the
set of fresh variables in the negation as failure changes, thats
why different solutions are obtained.
Bye
In short, yes, it is procedural.
Negation as failure uses a cut, and cuts are procedural concepts. You cannot use negation as failure in a declarative way - it is not possible.
It is worth mentioning that not all uses of cuts throw declarativeness out of the window - some of them just increase efficiency. But unfortunately, this is not the case with negation as failure - declarativeness goes out the window.
(Prolog is just a procedural prover disguised as a declarative language lol)