Re: where do I think wrong

Roelof Wobben <[email protected]>
Newsgroups gmane.comp.ai.prolog.swi
Message-ID <[email protected]>
 
> Subject: Re: [SWIPL] where do I think wrong
> From: [email protected]
> Date: Fri, 14 Mar 2014 10:20:28 +1300
> CC: [email protected]
> To: [email protected]
> 
> 
> On 13/03/2014, at 9:04 PM, Roelof Wobben wrote:
> > 
> > parent(mans,gerda).
> > parent(mans,roelof).
> > parent(marie,gerda).
> > parent(marie,roelof).
> > parent(dagmar,denise).
> > parent(dagmar,kimberly).
> > parent(ronald,denise).
> > parent(ronald,kimberly).
> > parent(chantal,tamara).
> > parent(roelof,tamara).
> > parent(jan,chantal).
> > parent(jan,dagmar).
> 
> (1) Where is the comment saying which argument is what?
>     Is mans a parent of gerda, or
>     is gerda a parent of mans?
> 
>     I entreat you in the name of suffering humanity,
>     ADD A COMMENT
>     % parent(P, C) is true when P and C are atoms
>     % naming people and P is one of C's parents.
> 
>     I am serious about the "suffering humanity" part.
>     Failing to provide this information waste people's
>     time as they scour the rest of your program for
>     clues about something they needed to know and you
>     knew and chose to conceal.  I don't care *what*
>     the programming language is, that's bad style.
> 
> (2) There is a key on your keyboard you may have
>     forgotten about, though it's easily the biggest
>     and easiest to use.  USE IT.  It's called the
>     space bar, and it's the big one at the bottom.
> 
>     Like most programming languages, Prolog uses the
>     comma for several things:
> 	- to separate goals
> 	=> put a newline after
> 	- to separate the arguments of goals
> 	=> put a space after
> 	- to separate the fields of data structures
> 	=> I usually prefer NOT to put a space, but
> 	   there are some who do, and I'll not say
> 	   they're wrong.
> 
>     When a construction has parts that need to be
>     *perceived* as parts, ensure that there is
>     enough white space.
> 
>     Again, this is largely language-independent.
>     If there is any programming language in which
>     it is good style to run the arguments of a
>     procedure together in one space-less blob, I
>     hope I never see it.
> 
> > is_father(F,C) :- 
> >   parent(F,C), male(F).
> 
> Better:
> 
>     father_child(Father, Child) :-
>         parent_child(Father, Child),
>         male(Father).
> 
> (3) You can get away with one-letter variable names in
>     toy programs, but it is a cruel habit to get into.
>     I once had to maintain a couple of thousand lines
>     of Prolog where every variable was one letter or
>     one letter and one digit, and I couldn't take a
>     step until I had changed all the names to something
>     meaningful.
> 
>     Again, this is largely language-independent.
>     BASIC was the last programming language I know of
>     to insist on 1-letter or 1-letter-1-digit names,
>     and modern BASIC doesn't do that any more.
> 
>     What if someone wrote
> 
> 	is_father(M,T) :- parent(M,T), male(M).
> 
>     (Looks obvious to _me_: M = Matua, T = Tamaiti.)
>     
> > have_children(M,F) :-
> >   is_mother(M,Z), 
> >   is_father(F,Z).
> 
> (3) To start with, this is a perfect example of how
>     one-letter names can confuse.  I initially read
>     "M" and "F" as "Male" and "Female" respectively...
> 
> (4) If you say in English that M and F "have children"
>     you are definitely implying that they have more than
>     one.  This predicate only tests whether they have at
>     least one.
> 
> (5) What's more, suppose
> 
> 	richard father-of abigail
> 	richard father-of susanna
> 	jeanene mother-of abigail
> 	jeanene mother-of susanna
> 
>     Then
> 	have_children(richard, jeanene)
>     can be proven true in two different ways.
>     You get this interaction:
> 
> 	?- have_children(Woman, richard).
> 	Woman = jeanene ;
> 	Woman = jeanene. 
> 
>     It is important to understand that Prolog doesn't find
>     *solutions* to your query, it finds *proofs*, and one
>     solution may have many proofs.
> 
>     We can fix that by putting hacky code here,
>     but the best way is to refactor the data design.
>     It's certainly what I would do if this were a
>     real data base.
> 
>     I would introduce 'consortships'.  (OED sense 2b.)
> 
>     So there would be facts
> 
> 	consortship_man(  273, richard).
> 	consortship_woman(273, jeanene).
> 
> 	parentage(abigail, 273).
> 	parentage(susanna, 273).
> 
>     or something like that, and rules
> 
>     man_and_woman_who_had_some_child(Man, Woman) :-
> 	consortship_man(Consortship, Man),
> 	consortship_woman(Consortship, Woman),
> 	once(parentage(_Child, Consortship)).
> 
>     child_father(Child, Father) :-
> 	parentage(Child, Consortship),
> 	consortship_man(Consortship, Father).
> 
>     or something like that.
> 
> > list_parents(C) :-
> >   parent(X,C), 
> >   tab(5), 
> >   write(X),
> >   nl, 
> >   fail.
> >   list_parents(_).
> 
> (6) I really dislike having the parts of a failure-driven loop
>     scattered across several clauses.  I find it clearer if
>     you have
> 
>     list_parents(Child) :-
> 	(   parent(Parent, Child),
> 	    tab(5), write(Parent), nl,
> 	    fail
> 	;   true
> 	).
> 
> > display_parents(C) :-
> >   write('De ouders van '), 
> >   write(C), 
> >   write(' zijn :'),
> >   nl, 
> >   nl,
> >   list_parents(C).
> >   display_parents(_).
> 
> (7) Here the second clause is worse than useless.
> > 
> > have_siblings(C) :-
> >    is_father(X,C),
> >    is_father(X,S), 
> >    is_mother(Y,S), 
> >    is_mother(Y,C), 
> >    C \= S,
> >    write(S).
> 
> (8) You really want to factor out the common pattern here.
> 
>     child_father_mother(Child, Father, Mother) :-
>         is_father(Father, Child),
> 	is_mother(Mother, Child).
> 
>     have_siblings(Child) :-
> 	child_father_mother(Child, Father, Mother),
> 	child_father_mother(Sibling, Father, Mother),
> 	Sibling \== Child,
> 	write(Sibling).
> 
> (9) You have a predicate whose purpose is to LIST
>     the siblings of someone, but you have named it
>     as if its purpose were to TEST whether someone
>     had any siblings.  Write
> 
>     are_full_siblings(Child, Sibling) :-
> 	child_father_mother(Child, Father, Mother),
> 	child_father_mother(Sibling, Father, Mother),
> 	Sibling \== Child.
> 
>     list_full_siblings_of(Child) :-
> 	foreach(are_full_siblings(Child, Sibling),
> 	    writeln(Sibling)).
> 
> > display_siblings(C) :-
> >   write('De broers/zusters van '), 
> >   write(C), 
> >   write(' zijn :'),
> >   nl, 
> >   nl,
> >   have_siblings(C).
> >   display_siblings(_).
> 
> (7) again.  Or it would be if have_siblings/1 were the
>     other half of the failure-driven loop you think it is.
>     With the list_siblings/1 predicate above, delete that
>     second clause.
> > 
> > 
> > It worked fine if a mother and father are known.
> > So I want to change it to this :
> > 
> > have_siblings(C) :-
> >    is_father(X,C),
> >    is_father(X,S); 
> >    is_mother(Y,S), 
> >    is_mother(Y,C), 
> >    C \= S,
> >    write(S).
> 
> (10)You have a scope issue with ';'.
> 
>     ALWAYS write
> 	(   <alternative 1>
> 	;   <alternative 2>
> 	...
> 	;   <alternative n>
> 	)
>     with the semicolons at the front, so they are
>     visibly NOT commas, and while there are times
>     that you don't really need the parentheses,
>     ALWAYS put them in.
> 
>     Do NOT put extra parentheses around each alternative,
>     they just make it harder to read.
> 
>     Again, you want to factor out "are these people half
>     siblings" from "show the half siblings of this person".
> 
>     are_half_or_fullsiblings(Child, Sibling) :-
> 	(   is_father(Father, Child),
> 	    is_father(Father, Sibling)
> 	;   is_mother(Mother, Child),
> 	    is_mother(Mother, Sibling)
> 	),
> 	Sibling \== Child.
> 
>     list_half_siblings(Child) :-
> 	foreach(are_half_or_full_siblings(Child, Sibling),
> 	    writeln(Sibling)).
> 
>     However, note that abigail and susanna are full siblings,
>     so they have the same father AND the same mother, so there
>     are TWO ways for are_half_siblings(abigail, susanna) to be
>     proven, and list_half_siblings(abigail) will write
>     susanna twice.
> 
>     One way to deal with that is to say that two people
>     are half_or_full siblings if they have the same father
>     or they have the same mother but NOT the same father.
> 
>     % In the following predicates, X and Y stand for
>     % people of indeterminate sex at the same genealogical level.
> 
>     same_father(X, Y) :-
>         is_father(Father, X),
> 	is_father(Father, Y).
> 
>     same_mother(X, Y) :-
> 	is_mother(Mother, X),
> 	is_mother(Mother, Y).
> 
>     half_siblings(X, Y) :-
> 	(   same_father(X, Y),
> 	    \+ same_mother(X, Y)
> 	;   same_mother(X, Y),
> 	    \+ same_father(X, Y)
> 	).
> 
>     half_or_full_siblings(X, Y) :-
>         (   same_father(X, Y),
> 	    X \== Y
> 	;   same_mother(X, Y),
> 	    \+ same_father(X, Y)
> 	).
> 
>     full_siblings(X, Y) :-
> 	same_father(X, Y),
> 	X \== Y,
> 	same_mother(X, Y).
> 
>     You can get away with using single-letter variables
>     if you set up an EXPLICIT convention for what they mean.
> 
>  Thanks for the long explanation.One last question where does /+ for.I know /== is not the same.  Roelof
  		 	   		  
-------------- next part --------------
HTML attachment scrubbed and removed
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.