In OWL:
There is a class X and the properties P1, P2, and P3, each of which has domain X.
I want to say:
Every instance of X must at least participate in a relation with one of the properties P1 or P3.
Every instance of X which participates in a relation with P2 must also participate in a relation with P1.
But every instance of X may only participate in relations with P1 and P2 or in relations with P3.
Maybe it is easier to understand with some syntax and labels:
:Chronology a owl:Class ;
rdfs:label "X" ;
:hasBegin a owl:DatatypeProperty ;
rdfs:label "P1" ;
rdfs:domain :Chronology .
:hasEnd a owl:DatatypeProperty ;
rdfs:label "P2" ;
rdfs:domain :Chronology .
:hasNoBeginNoEnd a owl:DatatypeProperty ;
rdfs:label "P3" ;
rdfs:domain :Chronology .
I understand the concept of anonymous classes and restrictions but nothing really seems to fit.
You have a few different constraints here, but they can all be represented in OWL. Let us address the constraints one at a time.
Every instance of X must at least participate in a relation with one of the properties P1 or P3.
This says that for every x, either there is a y such that P1(x,y), or there is a z such that P2(x,z). In OWL, this is expressed by
X SubClassOf ((P1 some Thing) or (P2 some Thing))
The class expression P1 some Thing represents the class of things that are related by P1 to some entity. Similarly for P2 some Thing. The subClassOf axiom as a whole says that “if something is an X, then it is either a P1 some Thing or a P2 some Thing.” (You could also use P min 1 instead of P some Thing, if you wanted to. It is not a significant difference.)
Every instance of X which participates in a relation with P2 must also participate in a relation with P1.
This says that for every x, if there is a y such that P2(x,y), then there is also a z such that P1(x,z). Another way of saying this is that “for every x, if x is an X and there is a y such that P2(x,y), then there is also a z such that P1(x,z).” This can be expressed by another subclass axiom:
(X and (P2 some Thing)) SubClassOf (P1 some Thing)
(For the sake of generality, I used X and (P2 some Thing) on the left side of this subclass axiom. In this specific case, since X is the domain of P2, we can infer that P2 some Thing is a subclass of X, so we could also have used just P2 some Thing on the left.)
But every instance of X may only participate in relations with P1 and P2 or in relations with P3.
This says that if some x is an X and there is a y such that P3(x,y), then there is no z such that P1(x,z) or P2(x,y), and vice versa. You can represent this in a few ways. You could use two subclass axioms:
(X and (P3 some Thing)) SubClassOf ((P1 max 0) and (P2 max 0))
(X and ((P1 some Thing) or (P2 some Thing))) SubClassOf (P3 max 0)
You could also use a single disjoint class axiom (notice that X appears on both sides)
(X and (P3 some Thing)) DisjointWith (X and ((P1 some Thing) or (P2 some Thing)))
(As I noted in the previous case, since the domain of the properties is X, the class X and (P3 some Thing) is equivalent to P3 some Thing. The left side of these subclass axioms could also be simply P3 some Thing and (P1 some Thing) or (P2 some Thing), and the classes in the disjoint axioms could be P3 some Thing and (P1 some Thing) or (P2 some Thing).)
Here's what the classes and axioms in the ontology looks like (in the N3 format):
:X a owl:Class ;
rdfs:subClassOf
[ a owl:Class ;
owl:unionOf ([ a owl:Restriction ;
owl:onProperty :P1 ;
owl:someValuesFrom owl:Thing
] [ a owl:Restriction ;
owl:onProperty :P2 ;
owl:someValuesFrom owl:Thing
])
] .
[] a owl:Class ;
rdfs:subClassOf
[ a owl:Restriction ;
owl:onProperty :P1 ;
owl:someValuesFrom owl:Thing
] ;
owl:intersectionOf (:X [ a owl:Restriction ;
owl:onProperty :P2 ;
owl:someValuesFrom owl:Thing
]) .
[] a owl:Class ;
owl:disjointWith
[ a owl:Class ;
owl:intersectionOf (:X [ a owl:Restriction ;
owl:onProperty :P3 ;
owl:someValuesFrom owl:Thing
])
] ;
owl:intersectionOf (:X [ a owl:Class ;
owl:unionOf ([ a owl:Restriction ;
owl:onProperty :P1 ;
owl:someValuesFrom owl:Thing
] [ a owl:Restriction ;
owl:onProperty :P2 ;
owl:someValuesFrom owl:Thing
])
]) .
Commentary on Blank Node Usage
As pointed out in the comments, the ontology above uses class expressions represented by blank nodes as the subjects of the two "general class axioms", i.e., the subclass axioms that related two class expressions, neither of which is a simple class identifier. The original OWL Web Ontology Language
Reference includes, in Appendix E: Rules of Thumb for OWL DL Ontologies:
Avoid orphan blank nodes
In general, blank nodes occurring in the graph either represent unnamed individuals, or should be exactly one of the following:
The object of an rdfs:subClassOf, owl:equivalentClass, owl:disjointWith, owl:someValuesFrom, owl:allValuesFrom or rdf:type triple.
The subject of an rdf:type triple with object owl:AllDifferent.
An element in an rdf:List.
Orphan blank nodes, i.e. those which are not the object of a triple are, in general, not allowed (other than the owl:AllDifferent case described above).
At first glance, it would seem that the ontology provided above violates this, because the "general class axioms" (class axioms whose subject is not a class identifier) have class expressions as their subject. However, section 3.2 Class Axioms gives the syntax of, e.g., rdfs:subClassOf axioms as
AXIOM SCHEMA: class description rdfs:subClassOf class description
That section also includes the note:
NOTE: In OWL Lite the subject of an rdfs:subClassOf statement must be a class identifier. The object must be either a class identifier or a property restriction.
This suggests that Appendix E is mistaken in omitting certain cases where "orphan blank nodes" are allowed. That suggestion isn't normative, of course; it opens with the introduction:
The following rules give an informal characterization of the conditions for an RDF graph to be a DL ontology. This is not intended to replace the characterization given in S&AS, but instead gives some general pointers — the idea is that if you stick to these guidelines, you're more likely to produce OWL DL ontologies. [emphasis added]
For confirmation, we need to look at section 8. OWL Full, OWL DL and OWL Lite, which describes the precise constructs that are allowed in OWL Full, OWL DL, and Owl Lite ontologies. That section reiterates that, in OWL Lite,
the subject of rdfs:subClassOf triples be class names and the object of rdfs:subClassOf triples be class names or restrictions;
but puts no such restrictions on OWL DL ontologies. Section 8 does require, for OWL DL ontologies, that
All axioms must be well-formed, with no missing or extra components, and must form a tree-like structure. The last constraint implies that all classes and properties that one refers to are explicitly typed as OWL classes or properties, respectively.
This points out that
[] rdfs:subClassOf :Foo .
is not valid OWL DL, but that
[] a owl:Class ;
rdfs:subClassOf :Foo .
is (provided that :Foo is an owl:Class, of course). The non-normative Appendix E simply missed a case where "orphan blank nodes" can be used. General class axioms don't get used all that often, except when some particularly complicated sentences need to be represented, so it's not a hard mistake to make.
For some more information about general class axioms, see Being complex on the left-hand-side: General Concept Inclusions.
Related
What is the systematic approach to extracting nouns as arguments from an expression in J? To be clear, an expression containing two literals should become a dyadic expression with the left and right arguments used instead of the literals.
I'm trying to learn tacit style so I prefer not to use named variables if it is avoidable.
A specific example is a simple die roll simulator I made:
>:?10#6 NB. Roll ten six sided dice.
2 2 6 5 3 6 4 5 4 3
>:?10#6
2 1 2 4 3 1 3 1 5 4
I would like to systematically extract the arguments 10 and 6 to the outside of the expression so it can roll any number of any sized dice:
d =. <new expression here>
10 d 6 NB. Roll ten six sided dice.
1 6 4 6 6 1 5 2 3 4
3 d 100 NB. Roll three one hundred sided dice.
7 27 74
Feel free to illustrate using my example, but I'm looking to be able to follow the procedure for arbitrary expressions.
Edit: I just found out that a quoted version using x and y can be automatically converted to tacit form using e.g. 13 : '>:?x#y'. If someone can show me how to find the definition of 13 : I might be able to answer my own question.
If your goal is to learn tacit style, it's better that you simply learn it from the ground up rather than try to memorize an explicit algorithm—J4C and Learning J are good resources—because the general case of converting an expression from explicit to tacit is intractable.
Even ignoring the fact that there have been no provisions for tacit conjunctions since J4, in the explicit definition of a verb you can (1) use control words, (2) use and modify global variables, (3) put expressions containing x and/or y as the operands of an adverb or conjunction, and (4) reference itself. Solving (1), (3), or (4) is very hard in the general case and (2) is just flat out impossible.*
If your J sentence is one of a small class of expressions, there is an easy way to apply the fork rules make it tacit, and this is what is more or less what is implemented in 13 :. Recall that
(F G H) y is (F y) G (H y), and x (F G H) y is (x F y) G (x H y) (Monad/Dyad Fork)
([: G H) y is G (H y), and x ([: G H) y is G (x H y) (Monad/Dyad Capped Fork)
x [ y is x, x ] y is y, and both of [ y and ] y are y (Left/Right)
Notice how forks use their center verbs as the 'outermost' verb: Fork gives a dyadic application of g, while Capped Fork gives a monadic one. This corresponds exactly to the two modes of application of a verb in J, monadic and dyadic. So a quick-and-dirty algorithm for making tacit a "dyadic" expression might look like the following, for F G H verbs and N nouns:
Replace x with (x [ y) and y with (x ] y). (Left/Right)
Replace any other noun n with (x N"_ y)
If you see the pattern (x F y) G (x H y), replace it with x (F G H) y. (Fork)
If you see the pattern G (x H y), replace it with x ([: G H) y. (*Capped Fork()
Repeat 1 through 4 until you attain the form x F y, at which point you win.
If no more simplifications can be performed and you have not yet won, you lose.
A similar algorithm can be derived for "monadic expressions", expressions only dependent on y. Here's a sample derivation.
<. (y - x | y) % x NB. start
<. ((x ] y) - (x [ y) | (x ] y)) % (x [ y) NB. 1
<. ((x ] y) - (x ([ | ]) y)) % (x [ y) NB. 3
<. (x (] - ([ | ])) y) % (x [ y) NB. 3
<. x ((] - ([ | ])) % [) y NB. 3
x ([: <. ((] - ([ | ])) % [)) y NB. 4 and we win
This neglects some obvious simplifications, but attains the goal. You can mix in various other rules to simplify, like the long train rule—if Train is a train of odd length then (F G (Train)) are equivalent (F G Train)—or the observation that x ([ F ]) y and x F y are equivalent. After learning the rules, it shouldn't be hard to modify the algorithm to get the result [: <. [ %~ ] - |, which is what 13 : '<. (y - x | y) % x' gives.
The fail condition is attained whenever an expression containing x and/or y is an operand to an adverb or conjunction. It is sometimes possible to recover a tacit form with some deep refactoring, and knowledge of the verb and gerundial forms of ^: and }, but I am doubtful that this can be done programmatically.
This is what makes (1), (3), and (4) hard instead of impossible. Given knowledge of how $: works, a tacit programmer can find a tacit form for, say, the Ackermann function without too much trouble, and a clever one can even refactor that for efficiency. If you could find an algorithm doing that, you'd obviate programmers, period.
ack1 =: (1 + ])`(([ - 1:) $: 1:)`(([ - 1:) $: [ $: ] - 1:)#.(, i. 0:)
ack2 =: $: ^: (<:#[`]`1:) ^: (0 < [) >:
3 (ack1, ack2) 3
61 61
TimeSpace =: 6!:2, 7!:2#] NB. iterations TimeSpace code
10 TimeSpace '3 ack1 8'
2.01708 853504
10 TimeSpace '3 ack2 8'
0.937484 10368
* This is kind of a lie. You can refactor the entire program involving such a verb through some advanced voodoo magic, cf. Pepe Quintana's talk at the 2012 J Conference. It isn't pretty.
13 : is documented in the vocabulary or NuVoc under : (Explicit).
The basic idea is that the value you want to be x becomes [ and the value you want to be y becomes ]. But as soon as the the rightmost token changes from a noun (value) to a verb like [ or ], the entire statement becomes a train, and you may need to use the verb [: or the conjunctions # or #: to restore the composition behavior you had before.
You can also replace the values with the actual names x and y, and then wrap the whole thing in ((dyad : ' ... ')). That is:
>:?10#6 NB. Roll ten six sided dice.
can become:
10 (dyad : '>: ? x # y') 6 NB. dyad is predefined. It's just 4.
If you only need the y argument, you can use monad, which is prefined as 3. The name verb is also 3. I tend to use verb : when I provide both a monadic and dyadic version, and monad when I only need the monadic meaning.
If your verb is a one-liner like this, you can sometimes convert it automatically to tacit form by replacing the 3 or 4 with 13.
I have some notes on factoring verbs in j that can help you with the step-by-step transformations.
addendum: psuedocode for converting a statement to tacit dyad
This only covers a single statement (one line of code) and may not work if the constant values you're trying to extract are being passed to a conjunction or adverb.
Also, the statement must not make any reference to other variables.
Append [ x=. xVal [ y =. yVal to the statement.
Substitute appropriate values for xVal and yVal.
Rewrite the original expression in terms of the new x and y.
rewrite statement [ x=. xVal [ y=. yVal as:
newVerb =: (4 : 0)
statement ] y NB. we'll fill in x later.
)
(xVal) newVerb yVal
Now you have an explicit definition in terms of x and y. The reason for putting it on multiple lines instead of using x (4 : 'expr') y is that if expr still contains a string literal, you will have to fiddle with escaping the single quotes.
Converting the first noun
Since you only had a pipeline before, the rightmost expression inside statement must be a noun. Convert it to a fork using the following rules:
y → (])
x → ]x ([)
_, __, _9 ... 9 → (_:), (__:), (_9:) ... (9:)
n → n"_ (for any other arbitrary noun)
This keeps the overall meaning the same because the verb you've just created is invoked immediately and applied to the [ y.
Anyway, this new tacit verb in parentheses becomes the core of the train you will build. From here on out, you work by consuming the rightmost expression in the statement, and moving it inside the parentheses.
Fork normal form
From here on out, we will assume the tacit verb we're creating is always a fork.
This new tacit verb isn't actually a fork, but we will pretend it is, because any single-token verb can be rewritten as a fork using the rule:
v → ([: ] v).
There is no reason to actually do this transformation, it's just so I can simplify the rule below and always call it a fork.
We will not use hooks because any hook can be rewritten as a fork with the rule:
(u v) → (] u [: v ])
The rules below should produce trains in this form automatically.
Converting the remaining tokens
Now we can use the following rules to convert the rest of the original pipeline, moving one item at a time into the fork.
For all of these rules, the (]x)? isn't J syntax. It means the ]x may or may not be there. You can't put the ] x in until you transform a usage of x without changing the meaning of the code. Once you transform an instance of x, the ]x is required.
Following the J convention, u and v represent arbitrary verbs, and n is an arbitrary noun. Note that these include verbs
tokens y u (]x)? (fork) ] y → tokens (]x)? (] u fork) ] y
tokens x u (]x)? (fork) ] y → tokens ]x ([ u fork) ] y
tokens n u (]x)? (fork) ] y → tokens (]x)? (n u fork) ] y
tokens u v (]x)? (fork) ] y → tokens u (]x)? ([: v fork) ] y
There are no rules for adverbs or conjunctions, because you should just treat those as part of the verbs. For example +:^:3 should be treated as a single verb. Similarly, anything in parentheses should be left alone as a single phrase.
Anyway, keep applying these rules until you run out of tokens.
Cleanup
You should end up with:
newVerb =: (4 : 0)
] x (fork) ] y
)
(xVal) newVerb yVal
This can be rewritten as:
(xVal) (fork) yVal
And you are done.
I would like to create a quotient type with quotient_type in Isabelle/HOL in which I would left "non-constructed" the non-empty set S and the equivalence relation ≡. The goal is for me to derive generic properties w.r.t. S and ≡ over the quotient-lifted set S/≡. In this way, it would be interesting that Isabelle/HOL accepts dependent types... But I was told that was not possible.
Hence, I tried this
(* 1. Defining an arbitrary set and its associated type *)
consts S :: "'a set"
typedef ('a) inst = "{ x :: 'a. ¬ S = ({} :: 'a set) ⟶ x ∈ S}" by(auto)
(* 2. Defining the equivalence relation *)
definition equiv :: "'a ⇒ 'a ⇒ bool" where
"equiv x y = undefined"
(* here needs a property of equivalence relationship... *)
(* 3. Defining the quotiented set *)
quotient_type ('a) quotiented_set = "('a inst × 'a inst)" / "equiv"
(* Hence, impossible end proof here... *)
Is this formalization, there appears to be two problems
I don't think this is the cleanest way to define an arbitrary set S as I can't specify it to be non-empty...
I can't define an arbitrary equivalence relation equiv with the definition nor the fun commands as they only allow me define "constructive-strongly normalizing-inductive" definitions only... And yet, I want to say that I just have some function equiv that satisfies properties of equivalence (reflexivity, symmetry, transitivity).
Do you have any idea ? Thanks.
HOL types cannot depend on values. So if you want to define a quotient type for an arbitrary non-empty set S and equivalence relation equiv using quotient_type, the arbitrary part must stay at the meta-level. Thus, S and equiv can either be axiomatized or defined such that you can convince yourself that you really have captured the desired notion of arbitrary.
If you axiomatize S and equiv, then you yourself are responsible that the axioms are consistent with the other axioms of HOL. You can do that with the command axiomatization as in
axiomatization S :: "'a set" where S_not_empty: "S ≠ {}"
For Isabelle/HOL, S is then a fixed constant of which you only know that it is not empty. You will never be able to instantiate S, because the arbitrariness only exists in the set-theoretic interpretation of Isabelle/HOL.
If you do not want to add new axioms, you can use specification instead:
consts S :: "'a set"
specification (S) S_not_empty: "S ≠ {}" by auto
With specification, you have to prove that your axioms are consistent, so there is no danger here. However, S no longer is absolutely arbitrary, because it is defined in terms of the choice operator Eps, as can be seen from the generated theorem S_def.
If you really want to study the theory of quotients within Isabelle/HOL, I recommend that you do not use types, but ordinary sets. There is the quotient operator op // and some theorems in the theory Equiv_Relations which is part of the library.
I am developing a predicate in Prolog and it is possible for it to terminate before the end of it.
For that reason I was looking for a command similar to return; (C++). I used a cut ! but I'm doubtful as to what it literally stands for and if it does exactly what return; does. Ex:
pred(X) :-
X = 1 -> do this, !; else do that,
write('x =/= 1').
void pred(int X) {
if (X = 1) {do this; return;} else do that;
cout << "x =/= 1";
}
Are the functions above exactly the same?
There is no direct correspondence of Prolog's execution mechanism and those of traditional imperative languages. So any analogy rather leads you on a dead path.
In your example, the cut has no effect whatsoever: The (->)/2 alone will already exclude the Else branch. In a sense it does a "tiny" cut on If and the alternative. Would there be another clause to pred/1, your cut would exclude that branch too.
Prolog's execution mechanism is much more complex. If you insist on an analogy in imperative languages, think of iterators. The cut causes all iterators in scope of the cut to produce a done on the next next. So it is a bit like a break. Somewhat. But only in a language that supports iterators in the first place.
If you want to learn Prolog, don't try to develop your notions out of these (half) broken analogies.
Better start by imagining what relations a Prolog predicate describes and approximate from that the meaning of a predicate. Procedural notions will fit in, one by one.
So you have some procedural code like this:
def foo():
if cond1:
handle_cond1()
return
if cond2:
handle_cond2()
return
do_other_stuff()
You can transform this in the procedural domain to have no explicit returns, first doing this:
def foo():
if cond1:
handle_cond1()
return
if cond2:
handle_cond2()
else:
do_other_stuff()
And then doing this:
def foo():
if cond1:
handle_cond1()
else:
if cond2:
handle_cond2()
else:
do_other_stuff()
Once you have eliminated the return statements you can transform this into Prolog:
foo :-
cond1 ->
handle_cond1
; (cond2 ->
handle_cond2
; do_other_stuff
).
There is no way to immediately succeed in Prolog. (You can immediately fail with fail). You will have to perform a transformation like this to achieve a similar flow. Best of all would be to follow #false's advice and learn Prolog on its own terms.
As was pointed out, Prolog doesn't map well to procedural thought.
I find the best way to think of a Prolog program and its "database" as a tree (forest?). The analogy is a bit rough since the graph contains cycles (recursion).
When you ask the prolog engine to determine the truth or falseness of a particular assertion (predicate), it commences to do a depth-first, left-to-right traversal of the tree using unification (pattern matching) to guide the traversal. When the traversal reaches a leaf node, the predicate is true. On backtracking, it... backtracks and continues the tree walk. When there are no more reachable leaf nodes, the predicate fails.
Prolog is a descriptive language: you describe the conditions for success in terms of predicate calculus. Then you simply let Prolog's inference engine find the applicable solutions. If you try to shoehorn procedural, imperative thought into the model, in addition to making things more difficult than they should otherwise be, in my experience, you're pretty much guaranteeing poor performance.
I found Leon Sterling and Eliot Shapiro's textbook, The Art of Prolog, to be invaluable and far more instructive and enlightening than Clocksin & Mellish's Programming in Prolog.
Edited to note: Your sample predicate
pred(X) :-
X = 1 -> do this , ! ; else do that ,
write('x =/= 1')
.
has some problems.
First, just like C or C# or other procedural languages where the and and or operators have different precedences so an expression like if ( a && b || c && d ) ... probably doesn't bind the way you think it does, due to operator precedence, your example predicate is probably not doing what you think it's doing: as written, it binds as
pred(X) :-
X=1 ->
( do_this , ! )
;
( do_that , write( 'x =/= 1' ) )
.
When what you probably wanted was
pred(X) :-
( X=1 ->
( do_this , ! )
;
do_that ,
) ,
write( 'x =/= 1' )
.
You need to use parentheses to omake your intended binding explicit:
pred(X) :-
( X=1 ->
( do_this , ! )
;
do_that
),
write('x =/= 1')
.
Further, the cut (!) in your example is unnecessary, since the implication operator -> acts as if there were a cut involved. This:
foo(X) :-
truthy(X) ->
writeln('truthy!')
;
writeln('falsy')
.
is pretty much exactly the same thing as
foo(X) :- truthy(X) , ! ,
writeln( 'truthy' ) .
foo(_) :- writeln( 'falsy' ) .
Third, you should make use of unification and pattern matching in the head. Ignoring the write/1, your example might make better sense as
pred(1) :- do_this , ! .
pred(X) :- do_that .
And in general, if you're learning prolog, I would say avoid the implication operator (and alternation (logical OR, ';'/2) in general. Prefer explicit predicates with multiple clauses to express choice. Instead of something like
foo(X) :- ( try_this(X) ; try_that(X) ; finally(X) ) .
prefer
foo(X) :- try_this(X) .
foo(X) :- try_that(X) .
foo(X) :- finally(X) .
And instead of implication:
foo(X) :- X=1 -> try_this(X) ; try_that(X) .
prefer something like this:
foo(1) :- ! , try_this(X) .
foo(X) :- try_that(X) .
I think it makes it easier to grok what's going on since it makes the choice points (and their elimination) explicit.
I would like to add that having solid coding guidelines can also help quite a bit to increase code readability and to avoid code brittleness.
Starting with #DanielLyons' code:
foo :-
cond1 ->
handle_cond1
; (cond2 ->
handle_cond2
; do_other_stuff
).
In practice, cascades of multiple nested if-then-else constructs occur: "if-then-elseif-then-elseif-then-elseif-then-...-else".
To increase readability, the code layout can be brushed up and the level of indentation adjusted:
foo :-
( cond1 -> handle_cond1
; cond2 -> handle_cond2
; do_other_stuff
).
Whenever code lines get too wide, a slightly less wide and more tall style may be preferable:
foo :-
( cond1
-> handle_cond1
; cond2
-> handle_cond2
; do_other_stuff
).
Is it possible, with reasonable effort, to visualize how PROLOG found the results to a query?
It would help to understand via which paths it found e.g. some repeating entries (e.g. finding a relative twice in a family tree query).
I can only find prolog-graph to perform simular task, but didn't try it yet. Authors claim that it "generates images of resolution trees for given Prolog queries".
As far as I can remember, the standard way to have an augmented pure Prolog interpreter is to augment a standard pure Prolog interpreter:
solve( T ) :-
( T = (A , B) -> solve(A) , solve(B)
; T = (A ; B) -> (solve(A) ; solve(B))
; T ).
We can use copy_term/2 on each step, and collect the copied terms into a difference list:
solve( T, [Q|R], Z ) :- copy_term(T,Q),
( T = (A , B) -> solve(A,R,S) , solve(B,S,Z)
; T = (A ; B) -> (solve(A,R,Z) ; solve(B,R,Z))
; T, R = Z ).
To be called as solve( AQuery, PathTaken, []).
Not tested.
I am trying to write a Prolog program that will print out the male successors of British Royalty in order. My attempt so far:
son(elizabeth, charles).
son(charles, william).
son(charles, henry).
son(elizabeth, andrew).
son(elizabeth, edward).
son(edward, severn).
successor(X, Y) :- son(X, Y).
successor(X, Y) :- son(X, C), successor(C, Y).
The successor function doesn't quite do what I want: the current output is this:
successor(elizabeth, Y).
Y = charles ;
Y = andrew ;
Y = edward ;
Y = william ;
Y = henry ;
Y = severn ;
false.
The first rule makes all three immediate children print out, then the second rule prints out all the descendants. But the descendants of the first child should come before the second immediate child, like this:
successor(elizabeth, Y).
Y = charles ;
Y = william ; % william and henry should come before andrew
Y = henry ;
Y = andrew ;
Y = edward ;
Y = severn ;
false.
This is my first Prolog program, and I am at a loss for how to express the right relationship. Can anyone give me an idea or pointers to resources that would be helpful to me?
As rati noted above, Prolog queries are resolved by choosing a rule, recursively evaluating it using depth-first search, then choosing the next rule and repeating the process. However, the particular rules you're starting with actually result in a breadth-first search of the family tree, which, as you noted, does not give output that matches the actual line of succession. Instead, you want to do a depth-first traversal of the royal family tree. This version gives the result you're looking for:
successor(X, Y) :- son(X, Z), (Y = Z; successor(Z, Y)).
Using this rule, Prolog resolves the query successor(X, Y) roughly as follows:
For each Z who is a son of X:
Bind Y to Z, giving Z as a solution.
The ; operator functions as a logical OR, so now Y is unbound and successor/2 is called recursively to get the successors who are sons of Z.
And yes, please do try to get a copy of the Art of Prolog. It's not the easiest programming book to read, but I found it extremely helpful in my (ongoing) attempt to understand logic programming. There seem to have been some cheap hardcover copies of the 1994 edition floating around eBay lately.
You said:
The first rule makes all three immediate children print out, then the second rule prints out all the descendants.
For any given predicate (such as successor/2), PROLOG will generally evaluate all the possible solutions for the 1st clause, then the next, etc. up to the last clause, in that order. Therefore, PROLOG will behave exactly as you've suggested above - solutions to immediate children will be found first, as the first clause of successor/2 does just that, and the second clause finds the descendants. If you were after a different order, try re-ordering the clauses (i.e.);
successor(X, Y) :- son(X, C), successor(C, Y).
successor(X, Y) :- son(X, Y).
This will cause PROLOG to evaluate to:
?- successor(elizabeth, Y).
Y = william ;
Y = henry ;
Y = severn ;
Y = charles ;
Y = andrew ;
Y = edward.
i.e., all descentants before immediate children.
The ordering you've suggested as wanting, however, can't be achieved through a simple reordering of these subgoals. Instead, consider the various tree traversal methods; i.e., in-order, pre-order and post-order. You could write a (simple) program which is capable of walking the tree structure in various different ways, instead of the default evaluation order for PROLOG. For example, consider the following new definition of successor/2:
successor(Parent, [Son|SonDescendents]) :-
son(Parent, Son),
successor(Son, SonDescendents).
This clause seeks to depth-first populate a list of children under a son, and will backtrack to find all solutions.
successor(NonParent, []) :-
\+ son(NonParent, _).
This next clause takes care of the base-case whereby the given individual does not have any sons, therefore no descendants enter the result list (empty).
Evaluating this gives:
?- successor(elizabeth, S).
S = [charles, william] ;
S = [charles, henry] ;
S = [andrew] ;
S = [edward, severn] ;
false.
ps. I highly recommend the following texts for learning PROLOG:
The Art of Prolog, by Leon Sterling and Ehud Shapiro
The Craft of Prolog, by Richard O'Keefe
Programming in Prolog, by Clocksin and Mellish
Your rule set looks good to me, it's giving you the right results, it's just printing them as it deduces them, which makes the order seem incorrect. Work through the results on paper and you will likely get a similar result.