?he 'SETS2''Page %'
?fo 'Aaron Sloman & Steve Hardy'- % -'\*(DY'
.sp2
.ce 2
PREDICATES - LISTS - SETS - LOGIC
========== = ===== = ==== = =====

.ce 1
Some basic procedural ideas.

.in +5
.ll -5
Some of these exercises are quite easy, others fairly advanced.
They will give you a lot of experience of list-processing, and using
"logical" concepts. Before trying these you should have worked through
at least the following two demos: LISTDEMO and NUMDEMO

You may find it helpful to read questions 24 and 25 before
doing anything else. They give examples of the sorts of problems
you should be able to solve after working through these exercises.
.in -5
.ll +5


1) A predicate is a function which produces the result TRUE or FALSE,
Standard predicates in POP11
include ISINTEGER, ISFUNC, ATOM, ISWORD. Predicates are frequently used in
IF statements, e.g:
 	: IF ISINTEGER(X) THEN ... ELSE ... CLOSE
.br
Here is a (new) predicate to decide whether a number is bigger than
ten:
 	: FUNCTION ABOVETEN(NUMBER);
 	:	NUMBER > 10
 	: END;
.br
Define predicates POSITIVE (TRUE if its argument is greater than
zero), NEGATIVE (TRUE if its argument is less than zero), EVEN (TRUE
if its argument leaves a zero remainder when divided by two) and ODD.
For the last two you may find it helpful to use the operator // and
the function ERASE. (You may also need the function NOT.)

2) What will be printed out by the following?
 	: ISINTEGER(1), ISINTEGER("A"), ISINTEGER(1+5) =>
 	: ISINTEGER([1]) =>
 	: ISINTEGER('1'), ISINTEGER(ISINTEGER)=>
 	: ISFUNC(ISINTEGER), ISFUNC(ISFUNC), ISFUNC(3), ISFUNC("A")=>
 	: ATOM(3) =>
 	: ATOM(ATOM), ATOM(ISINTEGER), ATOM("A"), ATOM([A B C])=>

3) Questions one and two were about predicates of one argument. The
operations =, >=, =<, > and < (see SYSVARS) can be
thought of as predicates as they too produce TRUE or FALSE (unless
there's an error!). They are sometimes called 'relations' or
'relational predicates' because they take two arguments, as in "X"=1.
We can write our own 'relational predicates':
 	: FUNCTION ISLESS(NUMBERONE,NUMBERTWO);
 	:	NUMBERONE < NUMBERTWO
 	: END;
.br
You will notice that most of the relations already defined in POP11
are also operations, which means that they can be executed by putting
their names between their arguments, as in X > 5. Not all system predicates are
like this, for example EQUAL. If you want to define new 'infix
functions' look at the section on operations in the SYNTAX
demo.
.br
As an exercise define a relation MUCHLESS of two arguments which
returns TRUE if its second argument exceeds its first by more than a
hundred.

4) Predicates can be applied to all sorts of things - not just numbers
as in most of the examples above. We could, for example, write a
function which given a 'thing' and a list return TRUE if the thing is
in the list and FALSE otherwise. This function is usually called
MEMBER since one might be thinking of the list as representing some
set. See if you can complete this (recursive) function definition:
.tp 6
 	: FUNCTION MEMBER(ITEM,LIST);
 	:	IF	LIST = []
 	:	THEN	<specify whether TRUE or FALSE>
 	:	ELSEIF	ITEM = HD(LIST)
 	:	THEN	<specify whether true or false>
 	:	ELSE	MEMBER(ITEM, TL(LIST))
 	:	CLOSE
 	: END;
.br
I would expect MEMBER(1,[]) to return (i.e. leave on the stack)
FALSE, MEMBER(1,[A B C D]) to return FALSE and MEMBER(1,[A B 1 2 C D])
to return TRUE. What would MEMBER("A",[A B 1 2 C D]) return? What
about MEMBER(1,[[1] [2] [3] [4]])?
Use TRACE MEMBER; for some illuminating print-out.

5) Use the function MEMBER to write a function called SUBSET which
takes two lists and returns TRUE if every element of the first list is
a MEMBER of the second, but FALSE otherwise.
.br
(I.e. SUBSET([2 4 3 1],[6 7 1 4 3 2 5])
should be TRUE but not SUBSET([E D],[A B C D]). What
would you expect the following to return?
.tp 3
 	: SUBSET([],[1 2 3 4])=>
 	: SUBSET([A E],[A B [E] D C])=>
 	: SUBSET("A",[A B C D])=>

6) If MEMBER(HD(L),TL(L)) is TRUE then the HD(L) must occur at least
twice in the list L. Can you use this fact to write a function, called
REDUNDANT, which, given a list, returns TRUE if there are any repeated
elements, so that:
.tp 4
 	: REDUNDANT([])=>
 	** 0
 	: REDUNDANT([1 3 5 2 1])=>
 	** <TRUE>
.br
What about REDUNDANT([[A] [B] [A]])? (Look at the difference between
= and EQUAL in SYSVARS).

7) What does the following function do? (Assume LIST is a list and
PRED a predicate.)
.tp 6
 	: FUNCTION EXISTS(LIST, PRED);
 	:	IF	LIST = []
 	:	THEN	FALSE
 	:	ELSEIF	PRED(HD(LIST))
 	:	THEN	TRUE
 	:	ELSE	EXISTS(TL(LIST),PRED)
 	:	CLOSE
 	: END;
.br
What will the following do (TRACE EXISTS for some of them):
.tp 4
 	: EXISTS([A B 1 2 3 E] , ISINTEGER)=>
 	: EXISTS([A B 1 2 3 E] , ISWORD)=>
 	: EXISTS([A B 1 2 3 E] , ISFUNC)=>
 	: EXISTS([%"A", "DOUBLE", "HD", TL%], ISFUNC)=>
.tp 6
We can use LAMBDA ..... END to create a function to be the second argument
of EXISTS, if a suitable function has not previously been defined, as in
 	: EXISTS([A 1 B 2 C 3], LAMBDA X; MEMBER(X,[2 4 6 8]) END)=>
.br
This checks whether there exists an element of [A 1 B 2 C 3] which is
also an element of [2 4 6 8].
Alternatively, instead of using LAMBDA to create a whole new function,
we can "partially apply MEMBER to a list to create a function which tests
if its argument is a member of the list, thus:
 	: EXISTS([A 1 B 2 C 3], MEMBER(%[2 4 6 8]%))=>
.br
For more on partial application see "(%" and "%)" in the SYSVARS demo.

8) Using a method similar to the previous function, or iteration if
you prefer, define a function called FINDONE which takes a list and
predicate as arguments. If there is an element of the list which
satisfies the predicate then FINDONE should produce the first such
element as its result; if there isn't one the result should be FALSE.
thus:
.tp 7
 	: FINDONE([A B 3 4 5],ISFUNC)=>
 	** <FALSE>
 	: FINDONE([A B 3 4 5],ISINTEGER)=>
 	** 3
.br
See if there is an ATOM (i.e. a non-list) in some list thus:
 	: FINDONE([[A B] [C D] [E]], ATOM) =>
 	** <FALSE>
 	: FINDONE([A B [A B] [C D] E], LAMBDA X; NOT(ATOM(X)) END)=>
 	** [A B]

9) Define a function ALL which, like EXISTS, takes two arguments LIST
and PRED and produces TRUE if PRED applied to every element of the
list produces TRUE, but FALSE if PRED of at least one element of the
list is FALSE. thus:
.tp 10
 	: ALL([2 4 6 8 A],ISINTEGER)=>
 	** <FALSE>
 	: ALL([2 4 6 8],ISINTEGER)=>
 	** <TRUE>
 	: ALL([A B C], LAMBDA X; MEMBER(X,[A 1 3 C 2 B]) END)=>
 	** <TRUE>
 	: ALL([A B C],MEMBER(%[A 1 3 C 2 B]%)=>
 	** <TRUE>
.br
What should ALL([],ISFUNC) produce? It may help to be reminded of the
SUBSET function from question 5.

10) Using the predicates ODD and EVEN (see question one) and the
function EXISTS (see question seven) define two predicates HASODD and
HASEVEN each of which takes a list and produces TRUE if at least one
element of the list is odd (for HASODD) or even (for HASEVEN).
.br
Similarly, using the function ALL define two predicates ALLODD and
ALLEVEN such that:
.tp 4
 	: ALLODD([1 3 5 6 7])=>
 	** <FALSE>
 	: ALLODD([1 3 5 7])=>
 	** <TRUE>

11) Define a function FINDALL which takes a list and a predicate and
produces as a result a list (possibly []) containing all the elements
of the first argument which produce TRUE when given as argument to the
second argument. e.g. FINDALL([A 1 B 2 C 3],ISINTEGER) should produce
the result [1 2 3].
.tp 6
 	: FUNCTION FINDALL(LIST,PRED);
 	:	IF	LIST = []
 	:	THEN	...
 	:	ELSEIF	PRED(HD(LIST))
 	:	THEN	[% ... %] <> FINDALL(..., ...)
 	:	ELSE	...
 	:	CLOSE
 	: END;
.br

12) What does the following function do?
.tp 6
 	: FUNCTION DELETE(ITEM,LIST);
 	:	IF	LIST = []
 	:	THEN	[]
 	:	ELSEIF	ITEM = HD(LIST)
 	:	THEN	TL(LIST)
 	:	ELSE	[%HD(LIST)%] <> DELETE(ITEM,TL(LIST))
 	:	CLOSE
 	: END;
.br
.tp 7
What will the following print?
 	: DELETE("B",[B])=>
 	: DELETE("B",[A B C])=>
 	: DELETE("B",[[A] [B] [C]])=>
 	: DELETE("B",[A B C D E])=>
 	: DELETE("B",[A B C B A])=>
 	: DELETE([B],[[A] [B] [C]])=>

13) Use the function EQUAL instead of the operation = to define a
version of DELETE such that DELETE([A B],[A B [A B]C D]) will produce
[A B C D].

14) Using DELETE define a function PRUNE which takes a list as
argument and produces a list as its result. The new list should
contain the same elements as the original one, but with all
redundancies removed (compare question 6).
Thus PRUNE([A B 1 2 C 2 1 B
A]) should produce [A B 1 2 C].

15) Using the function PRUNE (or the function DELETE) define a
function called UNION which takes two lists as arguments and produces
a new list which contains every element of the two arguments but with
no redundant elements, thus:
.tp 2
 	: UNION([A B C D],[E F C D])=>
 	** [A B C D E F]
.br
What about UNION([[A] [B] [C]], [[B] [C] [D]])? (see question 13).

16) Define a function called INTERSECTION which takes two lists as
arguments and returns a list of all the items common to both, thus:
.tp 2
 	: INTERSECTION([A B C D],[E C F D])=>
 	** [C D]

17) Define a function called LARGER which takes two lists as arguments
and produces the result TRUE if the first has MORE distinct elements
than the second, otherwise FALSE, thus:
.tp 4
 	: LARGER([A A A],[B C])=>
 	** <FALSE>
 	: LARGER([1 2 3],[A B A B])=>
 	** <TRUE>

18) Define a function called MORE which takes four arguments, thus:
.tp 3
 	: FUNCTION MORE(LIST1,PRED1,LIST2,PRED2);
 	:	...
 	: END;
.br
Where LIST1 and LIST2 are lists and PRED1 and PRED2 are predicates.
MORE is to return TRUE if the number of elements of LIST1 which
satisfy PRED1 is greater than the number of elements of LIST2 which
satisfy PRED2. thus:
.tp 8
 	: VARS LA; [1 2 3 A B]->LA;
 	: VARS LB; [1 2 B C D]->LB;
 	: MORE(LA,ISINTEGER,LB,ISINTEGER)=>
 	** <TRUE>
 	: MORE(LB,ISWORD,LA,ISINTEGER)=>
 	** <FALSE>
 	: MORE(LA,ISINTEGER,LA,ISWORD)=>
 	** <TRUE>
.br
What do you think should be done if one of the lists has repeated
elements?

19) Using MORE define a function, called MOST, which takes two
arguments - a list and a predicate - and returns TRUE iff MOST of the
elements of the list satisfy the predicate. Is there a better way to
define MOST than by using MORE?

20) Define a function called REMOVE which, when applied to a list and
a predicate produces a list containg all the elements of the list
which do NOT satisfy the predicate. Can you do this using FINDALL (see
question 11)?

21) Define a function called SUBTRACT which takes two lists, called
say LISTA and LISTB, and produces a new list of the elements of LISTA
which are not in LISTB. Thus:
.tp 2
 	: SUBTRACT([B C D E],[A B C D])=>
 	** [E]
.br
You may find it helpful to employ REMOVE and MEMBER, using the fact
that MEMBER partially applied to LISTA (i.e. MEMBER(%LISTA%)) is a
prediate TRUE only for the elements of LISTA.

22) Define a function called OVERLAP which takes two lists and
produces TRUE iff (i.e. if and only if) their INTERSECTION is
non-empty.

23) Define a function EXCLUDES which takes two lists and returns TRUE
iff the two lists do not OVERLAP.

24) Suppose there are ten people in a town, their names being A B C D
E F G H I J. You are told that the following pairs of people talk to
each other:
 	: [[A F] [F E] [G I] [H B] [C H] [J D] [G J] [B H] [D I]]
.br
Clearly(!) A, E and F form a 'sub-culture' whose members talk to each
other but not to the members of any other sub-culture in town. How
many sub-cultures are there? Define a function calles SUBCULTURE which
when given a list of two element lists (like that above) groups the
pairs together into larger lists, thus:
 	: SUBCULTRUE([[A B] [B C] [D E] [E F]])=>
 	** [[A B C] [D E F]]
 	: SUBCULTRUE([[A E] [B F] [C G] [D G]])=>
 	** [[A E] [B F] [C G D]]
.br
Can you see any purpose for a program like this? What if the input
were a list of pairs of towns connected by railway lines? Or a list of
pairs of numbers with common factors?
(Think about Guzman's program from the vacation reading).

25) Suppose you were given the following information about a set of
individuals A, B, C, D etc.
 	: A HAS PROPERTIES P1 P3 P5 AND P6.
 	: B HAS PROPERTIES P1 P3 P4 AND P7.
 	: C HAS PROPERTIES P2 P4 AND P5.
 	:  ...
.br
For example, the properties might be things like FEMALE, UNMARRIED,
HASCHILDREN, ISTEACHER, ISSPINSTER, TALL, BLONDE, BROWNHAIRED,
FAIRHAIRED etc.
.br
You are asked to make guesses about which properties can be wholly or
partially 'explained' in terms of the others. For example - are all
SPINSTERs UNMARRIED? Is being OVER6FT a sufficient condition for being
TALL? Is being UNMARRIED a sufficient condition for being a SPINSTER?
.br
Think about, and if possible develop, a program which can make 'good'
guesses about the answers to questions like these. For example to
refute the assertion that P1 is necessary for P2 find an individual of
which P2 is TRUE but not P1.
.br
You may want to assume that an individual lacks any property not
explicitly ascribed to her.
.br
Suppose individuals were to be described by association lists? (see
CONVERSE).
