home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #27 / NN_1992_27.iso / spool / comp / lang / pop / 43 < prev    next >
Encoding:
Internet Message Format  |  1992-11-17  |  6.4 KB

  1. From: kers@hplb.hpl.hp.com (Chris Dollin)
  2. Date: Tue, 17 Nov 1992 17:01:16 GMT
  3. Subject: An example
  4. Message-ID: <KERS.92Nov17170116@cdollin.hpl.hp.com>
  5. Organization: Hewlett-Packard Laboratories, Bristol, UK.
  6. Path: sparky!uunet!convex!news.utdallas.edu!wupost!usc!elroy.jpl.nasa.gov!sdd.hp.com!apollo.hp.com!cupnews0.cup.hp.com!scd.hp.com!hpscdm!hplextra!otter.hpl.hp.com!hpltoad!cdollin!kers
  7. Newsgroups: comp.lang.pop
  8. Distribution: comp
  9. Sender: news@hplb.hpl.hp.com (Usenet News Administrator)
  10. Lines: 142
  11. Nntp-Posting-Host: cdollin.hpl.hp.com
  12.  
  13.  
  14. Here, to whet peoples appetites, is an example of some code written in Pop11.
  15. It is the well-know shuffle-cards algorithm; here, it takes a list of thingies
  16. and delivers a new list of thingies. First, the code by itself:
  17.  
  18.     define shuffle( list ); lvars list, i;
  19.         lvars vec = {% list.dl %};
  20.         for i from vec.length by -1 to 2 do
  21.         lvars n = i.random;
  22.         unless n == i do (i.vec, n.vec) -> (n.vec, i.vec) endunless
  23.         endfor;
  24.         vec.destvector.conslist
  25.     enddefine;
  26.  
  27. And now the commentary.
  28.  
  29.     define shuffle( list ); lvars list, i;
  30.  
  31. defines a procedure called shuffle; that is to say, a variable assigned the
  32. value of the procedure. Because of the context (top-level), ``shuffle'' is a
  33. permanent variable; it persists until it is explicitly cancelled. (Actually, it
  34. persists until garbage-collected, which it won't be until it is (a) cancelled,
  35. so there's no route to it through the symbol table, and (b) no references to it
  36. remain in the system.)
  37.  
  38. Shuffle takes one argument, called ``list'', which is declared as a lexical
  39. variable (``lvar''). [The default, for historical reasons, would be as a
  40. dynamically local permanent variable; what Lisp would call a ``special''
  41. variable'']. We take the opportunity to declare another local lexical variable,
  42. ``i''. 
  43.  
  44.         lvars vec = {% list.dl %};
  45.  
  46. ``vec'' is another lexical, initialised to a vector (the ``{}'' brackets)
  47. constructed by evaluating the expression (the ``%%'' semi-brackets) ``list.dl''
  48. and gathering all the results up from the evaluation into the vector. The infix
  49. ``.'' is function application, with the function on the *right*; thus the
  50. function (found in) ``dl'' is applied to (the value of) ``list''. ``dl'' takes
  51. a list and explodes all of its elements onto the stack. (``dl'' stands for
  52. ``Destroy List'', although the list is not actually destroyed. ``Decompose'' is
  53. nearer the mark.)
  54.  
  55. Hence ``vec'' becomes a vector of all the elements of ``list'', in the same
  56. order. 
  57.  
  58.         for i from vec.length by -1 to 2 do
  59.  
  60. A simple counting-down for-loop. Sadly the control variable is not
  61. automatically declared for us (roll on Pop9X). ``length'' is a general
  62. procedure for finding the length of suitable things, such as vectors and lists.
  63.  
  64.             lvars n = i.random;
  65.  
  66. ``random'' is the library procedure for generating random numbers in the range
  67. 1 .. argument.
  68.  
  69.             unless n == i do (i.vec, n.vec) -> (n.vec, i.vec) endunless
  70.  
  71. The only reason for the ``unless'' is to do nothing in the case where we'd
  72. exchange an item with itself. ``do'' could be replaced by ``then''; the two are
  73. equivalent. The general Pop style is to use closing keywords obtained by
  74. sticking ``end'' on the front of the opening keyword.
  75.  
  76. ``->'' is the assignment arrow; the target(s) is(are) on the *right*. Here we
  77. see an assignment to a tuple, which means to assign to the components in
  78. right-to-left order. Because Pop is stack-based, the values to be assigned are
  79. waiting on the stack.
  80.  
  81. I said earlier that ``.'' was postfix application, yet here it is ``vec'' that
  82. is being applied, and I claimed that ``vec'' was a vector. What's going on?
  83. Well, in Pop *any* value can be applied. For vectors, it happens that
  84. application means indexing; one day someone will explain how this is arranged. 
  85.  
  86. Even supposing that application works for vectors, what's this assignment to a
  87. function call? Haven't matters become even more obscure? Perhaps. In Pop,
  88. procedures can come equipped with *updaters*, which are themselves procedures.
  89. The expression ``-> F(X)'' means ``(updater(F))( X )'', ie, when a call appears
  90. as the target of an assignment, the updater of the procedure is what gets
  91. called, rather than the procedure itself. For vectors, this means that the
  92. updater of the underlying indexing procedure is called, giving the desired
  93. result. 
  94.  
  95. [Compare Dylan where, for obscure reasons, updaters are associated with the
  96. *name* of a procedure, rather than the *value* of the procedure; or Common
  97. Lisp, where the nearest equivalent to updaters are the setf-macros.]
  98.  
  99.         endfor;
  100.  
  101. And here's the closing keyword for the for-statement.
  102.  
  103.         vec.destvector.conslist
  104.  
  105. ``destvector'' explodes the elements of the vector onto the stack, and then
  106. pushes the length of the vector. ``conslist'' takes an argument N, and the next
  107. N elements off the stack, and makes them into a list, bottom-most elements at
  108. the front of the list. Thus we have converted a vector to a list. I might
  109. instead have written ``[% vec.explode %]'', similar to the initialisation
  110. expression for ``vec'', but I wanted to make a different point. ``[]'' are list
  111. brackets, just as ``{}'' are vector brackets.
  112.  
  113.     enddefine;
  114.  
  115. And here's the closing keyowrd for the procedure definition. Trying it out:
  116.  
  117. shuffle( [a b c d] ) =>
  118. ** [d c b a]
  119. shuffle( [a b c d] ) =>
  120. ** [c a d b]
  121. shuffle( [a b c d] ) =>
  122. ** [b a c d]
  123. shuffle( [a b c d e f g h i] ) =>
  124. ** [i b h c g e f a d]
  125.  
  126. Now, this code is not particularly efficient. Most notably, it is using pretend
  127. calls (``i.vec'', etc) to get at vector elements; becuase there is no static
  128. typing [*1] the checks to see that ``vec'' has an applyable type, and to call
  129. the indexer, will take a fair amount of time. There are ways round this, which
  130. I will not address here; I'd hope to tempt Steve [*2] to do that. It also
  131. creates, and leaves as garbage, the vector ``vec''.
  132.  
  133. Let me know if this has been an interesting exercise for the non-Pop audience.
  134. I'm happy to provide more snippets to illustrate the language.
  135.  
  136. ----------------
  137.  
  138. [*1] The nearest thing to static typing is a ``procedure'' declaration that
  139. arranges that procedure-valued variables can be called *quickly* (no dynamic
  140. check needed) at the cost of checking every assignment to the variable. There
  141. are also forms of constant declaration, if you think of those as being types.
  142.  
  143. [*2] Steve Knight, Pop hacker and efficiency guru here at Bristol.
  144.  
  145.  
  146.  
  147.  
  148.  
  149.  
  150.  
  151. --
  152.  
  153. Regards,    | I'd say that semantically C is a ramshackle hut   | Meilir
  154. Kers.       | and C++ is a two-storey ramshackle hut.           | Page-Jones
  155.