Lesson_6.red 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. COMMENT
  2. REDUCE INTERACTIVE LESSON NUMBER 6
  3. David R. Stoutemyer
  4. University of Hawaii
  5. COMMENT This is lesson 6 of 7 REDUCE lessons. A prerequisite is to
  6. read an introductory text about LISP, such as "A Concise Introduction
  7. to LISP" by David L. Matuszek, which is freely available at
  8. https://www.cis.upenn.edu/~matuszek/LispText/lisp.html. Then
  9. familiarize yourself with the Standard Lisp Report, which is freely
  10. available via http://reduce-algebra.sourceforge.net/documentation.php.
  11. To avoid confusion between RLISP and the SYMBOLIC-mode algebraic
  12. algorithms, this lesson will treat only RLISP. Lesson 7 deals with how
  13. the REDUCE algebraic mode is implemented in RLISP and how the user can
  14. interact directly with that implementation. That is why I suggested
  15. that you run this lesson in RLISP rather than full REDUCE. If you
  16. forgot or do not have a locally available separate RLISP, then please
  17. switch now to symbolic mode by typing the statement SYMBOLIC.;
  18. symbolic;
  19. pause;
  20. COMMENT Your most frequent mistakes are likely to be forgetting to quote
  21. data examples, using commas as separators within lists, and not putting
  22. enough levels of parentheses in your data examples.
  23. Having learnt from reading the Standard Lisp Report about the built-in
  24. RLISP functions CAR, CDR, CONS, ATOM, EQ, NULL, LIST, APPEND, REVERSE,
  25. DELETE, MAPLIST, MAPCON, LAMBDA, FLAG, FLAGP, PUT, GET, DEFLIST,
  26. NUMBERP, ZEROP, ONEP, AND, EVAL, PLUS, TIMES, CAAR, CADR, etc., here
  27. is an opportunity to reinforce the learning by practice. Write
  28. expressions using CAR, CDR, CDDR, etc. (which are defined only through
  29. 4 letters between C and R) to individually extract each atom from F,
  30. where:;
  31. f := '((john . doe) (1147 hotel street) honolulu);
  32. pause;
  33. COMMENT My solutions are CAAR F, CDAR F, CAADR F, CADADR F, CADDR CADR
  34. F, and CADDR F.
  35. Although commonly the "." is only mentioned in conjunction with data, we
  36. can also use it as an infix alias for CONS. Do this to build from F and
  37. from the data 'MISTER the s-expression consisting of F with MISTER
  38. inserted before JOHN.DOE;
  39. pause;
  40. COMMENT My solution is ('MISTER . CAR F) . CDR F.
  41. Enough of these inane exercises -- let's get on to something useful!
  42. Let's develop a collection of functions for operating on finite sets.
  43. We will let the elements be arbitrary s-expressions, and we will
  44. represent a set as a list of its elements in arbitrary order, without
  45. duplicates.
  46. Here is a function which determines whether its first argument is a
  47. member of the set which is its second element;
  48. symbolic procedure memberp(elem, set1);
  49. COMMENT Returns T if s-expression ELEM is a top-level element
  50. of list SET1, returning NIL otherwise;
  51. if null set1 then nil
  52. else if elem = car set1 then t
  53. else memberp(elem, cdr set1);
  54. memberp('blue, '(red blue green));
  55. COMMENT This function illustrates several convenient techniques for
  56. writing functions which process lists:
  57. 1. To avoid the errors of taking the CAR or the CDR of an atom,
  58. and to build self confidence while it is not immediately
  59. apparent how to completely solve the problem, treat the trivial
  60. cases first. For an s-expression or list argument, the most
  61. trivial cases are generally when one or more of the arguments
  62. are NIL, and a slightly less trivial case is when one or more
  63. is an atom. (Note that we will get an error message if we use
  64. MEMBERP with a second argument which is not a list. We could
  65. check for this, but in the interest of brevity, I will not
  66. strive to make our set-package give set-oriented error
  67. messages.)
  68. 2. Use CAR to extract the first element and use CDR to refer to
  69. the remainder of the list.
  70. 3. Use recursion to treat more complicated cases by extracting the
  71. first element and using the same functions on smaller
  72. arguments.;
  73. pause;
  74. COMMENT To make MEMBERP into an infix operator we make the declaration:;
  75. infix memberp;
  76. '(john.doe) memberp '((fig.newton) fonzo (santa claus));
  77. COMMENT Infix operators associate left, meaning expressions of the form
  78. (operand1 operator operand2 operator ... operator operandN)
  79. are interpreted left-to-right as
  80. ((...(operand1 operator operand2) operator ...) operator operandN).
  81. Operators may also be flagged RIGHT by
  82. FLAG ('(op1 op2 ...), 'RIGHT).
  83. to give the interpretation
  84. (operand1 operator (operand2 operator (... operandN))...).
  85. Of the built-in operators, only ".", "*=", "+", and "*" associate right.
  86. If we had made the infix declaration before the function definition, the
  87. latter could have begun with the more natural statement
  88. SYMBOLIC PROCEDURE ELEM MEMBERP SET.
  89. Infix functions can also be referred to by functional notation if one
  90. desires. Actually, an analogous infix operator named MEMBER is
  91. already built-into RLISP, so we will use MEMBER rather than MEMBERP
  92. from here on. (But note that MEMBER returns the sublist beginning
  93. with the first argument rather than T.);
  94. member(1147, cadr f);
  95. COMMENT Inspired by the simple yet elegant definition of MEMBERP, write
  96. a function named SETP which uses MEMBER to check for a duplicate element
  97. in its list argument, thus determining whether or not the argument of
  98. SETP is a set;
  99. pause;
  100. COMMENT My solution is;
  101. symbolic procedure setp candidate;
  102. COMMENT Returns T if list CANDIDATE is a set, returning NIL
  103. otherwise;
  104. if null candidate then t
  105. else if car candidate member cdr candidate then nil
  106. else setp cdr candidate;
  107. setp '(kermit, (cookie monster));
  108. setp '(dog cat dog);
  109. COMMENT If you used a BEGIN-block, local variables, loops, etc., then
  110. your solution is surely more awkward than mine. For the duration of
  111. the lesson, try to do everything without groups, BEGIN-blocks, local
  112. variables, assignments, and loops. Everything can be done using
  113. function composition, conditional expressions, and recursion. It will
  114. be a mind-expanding experience -- more so than transcendental
  115. meditation, psilopsybin, and EST. Afterward, you can revert to your
  116. old ways if you disagree.
  117. Thus endeth the sermon.
  118. Incidentally, to make the above definition of SETP work for non-list
  119. arguments all we have to do is insert "ELSE IF ATOM CANDIDATE THEN
  120. NIL" below "IF NULL CANDIDATE THEN T".
  121. Now try to write an infix procedure named SUBSETOF, such that SET1
  122. SUBSETOF SET2 returns NIL if SET1 contains an element that SET2 does
  123. not, returning T otherwise. You are always encouraged, by the way, to
  124. use any functions that are already builtin, or that we have previously
  125. defined, or that you define later as auxiliary functions.;
  126. pause;
  127. COMMENT My solution is;
  128. infix subsetof;
  129. symbolic procedure set1 subsetof set2;
  130. if null set1 then t
  131. else if car set1 member set2 then cdr set1 subsetof set2
  132. else nil;
  133. '(roof door) subsetof '(window door floor roof);
  134. '(apple banana) subsetof '((apple cobbler) (banana creme pie));
  135. COMMENT Two sets are equal when they have identical elements, not
  136. necessarily in the same order. Write an infix procedure named EQSETP
  137. which returns T if its two operands are equal sets, returning NIL
  138. otherwise.;
  139. pause;
  140. COMMENT The following solution introduces the PRECEDENCE declaration:;
  141. infix eqsetp;
  142. precedence eqsetp, =;
  143. precedence subsetof, eqsetp;
  144. symbolic procedure set1 eqsetp set2;
  145. set1 subsetof set2 and set2 subsetof set1;
  146. '(ballet tap) eqsetp '(tap ballet);
  147. '(pine fir aspen) eqsetp '(pine fir palm);
  148. COMMENT The precedence declarations make SUBSETOF have a higher
  149. precedence than EQSETP and make the latter have higher precedence than
  150. "=", which is higher than "AND". Consequently, these declarations
  151. enabled me to omit parentheses around "SET1 SUBSUBSETOF SET2" and
  152. around "SET2 SUBSETOF SET1". All prefix operators have higher
  153. precedence than any infix operator, and to inspect the ordering among
  154. the latter, we merely inspect the value of the global variable named;
  155. preclis!*;
  156. COMMENT Now see if you can write a REDUCE infix function named
  157. PROPERSUBSETOF, which determines if its left operand is a proper
  158. subset of its right operand, meaning it is a subset which is not equal
  159. to the right operand.;
  160. pause;
  161. COMMENT All of the above exercises have been predicates. In contrast,
  162. the next exercise is to write a function called MAKESET, which returns
  163. a list which is a copy of its argument, omitting duplicates.;
  164. pause;
  165. COMMENT How about:;
  166. symbolic procedure makeset lis;
  167. if null lis then nil
  168. else if car lis member cdr lis then makeset cdr lis
  169. else car lis . makeset cdr lis;
  170. COMMENT As you may have guessed, the next exercise is to implement an
  171. operator named INTERSECT, which returns the intersection of its set
  172. operands.;
  173. pause;
  174. COMMENT Here is my solution:;
  175. infix intersect;
  176. precedence intersect, subsetof;
  177. symbolic procedure set1 intersect set2;
  178. if null set1 then nil
  179. else if car set1 member set2
  180. then car set1 . cdr set1 intersect set2
  181. else cdr set1 intersect set2;
  182. COMMENT Symbolic-mode REDUCE has a built-in function named SETDIFF,
  183. which returns the set of elements which are in its first argument but
  184. not the second. See if you can write an infix definition of a similar
  185. function named DIFFSET.;
  186. pause;
  187. COMMENT Presenting --:;
  188. infix diffset;
  189. precedence diffset, intersect;
  190. symbolic procedure left diffset right;
  191. if null left then nil
  192. else if car left member right then cdr left diffset right
  193. else car left . (cdr left diffset right);
  194. '(seagull wren condor) diffset '(wren lark);
  195. COMMENT The symmetric difference of two sets is the set of all
  196. elements which are in only one of the two sets. Implement a
  197. corresponding infix function named SYMDIFF. Look for the easy way!
  198. There is almost always one for examinations and instructional
  199. exercises.;
  200. pause;
  201. COMMENT Presenting --:;
  202. infix symdiff;
  203. precedence symdiff, intersect;
  204. symbolic procedure set1 symdiff set2;
  205. append(set1 diffset set2, set2 diffset set1);
  206. '(seagull wren condor) symdiff '(wren lark);
  207. COMMENT We can use APPEND because the two set differences are
  208. disjoint.
  209. The above set of exercises (exercises of set?) have all returned set
  210. results. The cardinality, size, or length of a set is the number of
  211. elements in the set. More generally, it is useful to have a function
  212. which returns the length of its list argument, and such a function is
  213. built-into RLISP. See if you can write a similar function named
  214. SIZEE.;
  215. pause;
  216. COMMENT Presenting --:;
  217. symbolic procedure sizee lis;
  218. if null lis then 0
  219. else 1 + sizee cdr lis;
  220. sizee '(how marvelously concise);
  221. sizee '();
  222. COMMENT Literal atoms, meaning atoms which are not numbers, are stored
  223. uniquely in LISP and in RLISP, so comparison for equality of literal
  224. atoms can be implemented by comparing their addresses, which is
  225. significantly more efficient than a character-by-character comparison
  226. of their names. The comparison operator "EQ" compares addresses, so
  227. it is the most efficient choice when comparing only literal atoms.
  228. The assignments
  229. N2 := N1 := 987654321,
  230. S2 := S1 := '(FROG (SALAMANDER.NEWT)),
  231. make N2 have the same address as N1 and make S2 have the same address
  232. as S1, but if N1 and N2 were constructed independently, they would not
  233. generally have the same address, and similarly for S1 vs. S2. The
  234. comparison operator "=", which is an alias for "EQUAL", does a general
  235. test for identical s-expressions, which need not be merely two
  236. pointers to the same address. Since "=" is built-in, compiled, and
  237. crucial, I will define my own differently-named version denoted "..="
  238. as follows:;
  239. pause;
  240. newtok '((!. !. !=) myequal);
  241. infix eqatom, myequal;
  242. precedence myequal, equal;
  243. precedence eqatom, eq;
  244. symbolic procedure s1 myequal s2;
  245. if atom s1 then
  246. if atom s2 then s1 eqatom s2
  247. else nil
  248. else if atom s2 then nil
  249. else car s1 myequal car s2 and cdr s1 myequal cdr s2;
  250. symbolic procedure a1 eqatom a2;
  251. if numberp a1 then
  252. if numberp a2 then zerop(a1-a2)
  253. else nil
  254. else if numberp a2 then nil
  255. else a1 eq a2;
  256. COMMENT Here I introduced a help function named EQATOM, because I was
  257. beginning to become confused by detail when I got to the line which
  258. uses EQATOM. Consequently, I procrastinated on attending to some fine
  259. detail by relegating it to a help function which I was confident could
  260. be successfully written later. After completing MYEQUAL, I was
  261. confident that it would work provided EQATOM worked, so I could then
  262. turn my attention entirely to EQATOM, freed of further distraction by
  263. concern about the more ambitious overall goal. It turns out that
  264. EQATOM is a rather handy utility function anyway, and practice helps
  265. develop good judgement about where best to so subdivide tasks. This
  266. psychological divide-and-conquer programming technique is important in
  267. most other programming languages too.
  268. "..=" is different from our previous examples in that "..=" recurses
  269. down the CAR as well as down the CDR of an s-expression.;
  270. pause;
  271. COMMENT If a list has n elements, our function named MEMBERP or the
  272. equivalent built-in function named MEMBER requires on the order of n
  273. "=" tests. Consequently, the above definitions of SETP and MAKESET,
  274. which require on the order of n membership tests, will require on the
  275. order of n^2 "=" tests. Similarly, if the two operands have m and n
  276. elements, the above definitions of SUBSETOF, EQSETP, INTERSECT,
  277. DIFFSET, and SYMDIFF require on the order of m*n "=" tests. We could
  278. decrease the growth rates to order of n and order of m+n respectively
  279. by sorting the elements before giving lists to these functions. The
  280. best algorithms sort a list of n elements in the order of n*log(n)
  281. element comparisons, and this need be done only once per input set.
  282. To do so we need a function which returns T if the first argument is
  283. "=" to the second argument or should be placed to the left of the
  284. second argument. Such a function, named ORDP, is already built-into
  285. symbolic-mode REDUCE, based on the following rules:
  286. 1. Any number orders left of NIL.
  287. 2. Larger numbers order left of smaller numbers.
  288. 4. Literal atoms order left of numbers.
  289. 3. Literal atoms order among themselves by address, as determined
  290. by the built-in RLISP function named ORDERP.
  291. 5. Non-atoms order left of atoms.
  292. 6. Non-atoms order among themselves according to ORDP of their
  293. CARs, with ties broken according to ORDP of their CDRs.
  294. Try writing an analogous function named MYORD, and, if you are in
  295. REDUCE rather than RLISP, test its behavior in comparison to ORDP.;
  296. pause;
  297. COMMENT Whether or not we use sorted sets, we can reduce the
  298. proportionality constant associated with the growth rate by replacing
  299. "=" by "EQ" if the set elements are restricted to literal atoms.
  300. However, with such elements we can use property-lists to achieve the
  301. growth rates of the sorted algorithms without any need to sort the
  302. sets. On any LISP system that is efficient enough to support REDUCE
  303. with acceptable performance, the time required to access a property of
  304. an atom is modest and very insensitive to the number of distinct atoms
  305. in the program and data. Consequently, the basic technique for any of
  306. our set operations is:
  307. 1. Scan the list argument or one of the two list arguments,
  308. flagging each element as "SEEN".
  309. 2. During the first scan, or during a second scan of the same
  310. list, or during a scan of the second list, check each element
  311. to see whether or not it has already been flagged, and act
  312. accordingly.
  313. 3. Make a final pass through all elements which were flagged to
  314. remove the flag "SEEN". (Otherwise, we may invalidate later set
  315. operations which utilize any of the same atoms.)
  316. We could use indicators rather than flags, but the latter are slightly
  317. more efficient when an indicator would have only one value (such as
  318. having "SEEN" as the value of an indicator named "SEENORNOT").
  319. As an example, here is INTERSECT defined using this technique;
  320. symbolic procedure intersect(s1, s2);
  321. begin scalar ans, set2;
  322. flag(s1, 'seen);
  323. set2 := s2;
  324. while set2 do <<
  325. if flagp(car set2, 'seen) then ans := car set2 . ans;
  326. set2 := cdr set2 >>;
  327. remflag(s1, 'seen);
  328. return ans
  329. end;
  330. COMMENT Perhaps you noticed that, having used a BEGIN-block, group,
  331. loop, and assignments, I have not practiced what I preached about
  332. using only function composition, conditional expressions, and
  333. recursion during this lesson. Well, now that you have had some
  334. exposure to both extremes, I think you should always fairly consider
  335. both together with appropriate compromises, in each case choosing
  336. whatever is most clear, concise, and natural. For set operations
  337. based on the property-list approach, I find the style exemplified
  338. immediately above most natural.
  339. As your last exercise for this lesson, develop a file containing a
  340. package for set operations based upon either property-lists or
  341. sorting.
  342. This is the end of lesson 6. When you are ready to run the final
  343. lesson 7, load a fresh copy of REDUCE.
  344. ;end;