To save your work in SWISH, choose Save... from the File menu. Make your file NON-public (which really just makes it non-searchable), and fill in the following information:
Name: | [Choose your own, or let it generate one randomly] |
Title: | Sally Smith, CMSC 331, Prolog assignment 1 |
Author: | ssmith99@umbc.edu |
No tags are needed because you are not making the file public.
On saves after the first one, it will prompt you to describe your changes. This is not necessary, but is good practice.
Once you have saved your work, your location bar will display the URL, e.g., http://swish.swi-prolog.org/p/bgopGhEv.pl. You can use this URL to access your saved work in subsequent sessions. The URL can be accessed by anyone, so do not share it with anyone but the instructor. For this reason, you should allow the name to be generated randomly, or choose one that will not be easily guessed. (You also should not lose it! You may want to save your work in a local file as well.)
To submit your work, e-mail me at smatuszek@umbc.edu with the URLs of your two programs. You can do this at any time; I will not grade them until after the due date.
The due date is midnight on Sunday, November 15.
The basic facts should be expressed as female/1
, male/1
,
parent/2
, and married/3
.
Implement the following predicates:
mother/2
father/2
son/2
daughter/2
sister/2
(remember, you cannot be your own sister)
brother/2
(or your own brother... or your own anything)
grandfather/2
grandmother/2
uncle/2
aunt/2
first_cousin/2
ancestor/2
descendant/2
married/2
(this should be concluded from existing married/3
facts -- we will discuss this
in class)
stepmother/2
stepfather/2
relative/2
(includes relatives by both blood and marriage)
For each predicate, you should provide
For example:
/** examples ?- brother(leonardo, donatello). (true) ?- brother(leonardo, leonardo). (false) ?- brother(leonardo, X). (X = donatello, X = michaelangelo, X = raphael) */Note that you can put comments after the period in the examples block.
This may look like a lot of work, but most of these are trivial!
first/2
returns the first element in the list.
last/2
returns the last element in the list.
min/2
returns the smallest element in the list.
max/2
returns the largest element in the list.
sum/2
returns the sum of all elements in the list.
count/2
returns the number of elements in the list.
mean/2
returns the arithmetic mean of the elements in the list.
median/2
length/2
for count/2
, but I still want you to implement them recursively.
mean([1, 2, 3, 8], X).
should return X = 3.5
.
is/2
to perform calculations, e.g.
X is 3 + 4.
=> X = 7
.
first/2
, last/2
, min/2
, max/2
, mean/2
,
and median/2
should not return anything for empty lists.
We will discuss lists in class on Thursday. Remember the basic syntax:
[]
is the empty list.
|
is the list composition operator.
[Head|Tail]
represents the list whose first element is Head
and whose remaining sublist is Tail
. This is much like car
and cdr
.
[Head|[]]
represents the list whose first element is Head
and whose remaining sublist is the empty list, i.e., the list with only one element [Head]
.
last([Head|[]], Head).
("the last element of a list with only one element is that element")
and a recursive case:
last([_|Tail], X) :- last(Tail, X).
("the last element of a list is the last element of the tail of that list.")
Yes, this is almost inevitable given how Prolog works. For example, if siblings only have to share one parent to be siblings, then siblings that share both parents will be returned twice because there are two ways to prove that they are siblings.
Should aunt/uncle include your parents' siblings' spouses, or just your parents' siblings?
Yes, it should include your parents' siblings' spouses. But it does not have to include your parents' siblings' spouses' siblings.
For the examples that return false, should we just use someone outside the family tree, or someone who has a relationship but not that one?
It would be better to use someone who is inside the family tree. It would be trivially easy to just use the same unrelated person for every single false example. Don't do that!
Instead, try to use examples that will actually test edge cases. For example, when
testing cousin/2
, ask whether two siblings are cousins, since an incomplete
definition of cousin/2
would incorrectly return true when asked about two siblings.
I will be running my own tests in addition to the examples anyway, so it's a good thing to test them carefully.
What should count/2
do?
It should return the number of elements in the list. Yes, this could be done trivially with a built-in function, but I would like you to implement it yourself, to get experience with the standard recursive approach.