In comp.lang.pop, bh@anarres.CS.Berkeley.EDU (Brian Harvey) writes:
> Of course, these examples are entirely equivalent to what could be done
> in Lisp. I think you should post examples using some of the more unusual
> POP features, such as pattern matching.
Pop is very closely related to the Lisp family of languages, so it should
come as no surprise that many programs look similiar. The main reasons
for choosing to write in Pop rather than Lisp are aesthetic ones, in
my view. For example, the lack of distinction between the empty list
(nil) and the false value (false) in almost all Lisps is, to the eyes of
many Poppers like myself, clunky and ugly. But in practical programming
such differences are not a big deal.
The key difference between Lisp and Pop's semantics (putting the
important issue of syntax aside for one moment) is the open stack.
After all, the Pop pattern-matcher is a nice idea, incorrectly
implemented, but trivial to duplicate in extensible languages such as
Lisp or Prolog. Having the open stack at the heart of all programming
idioms gives the language family its distinctive character.
One idiom will illustrate my point nicely. The task is (say) to
add all the numbers in a list. One of the built-in routines is
called "applist" which takes a list and a procedure as arguments.
It then applies the procedure to each element of the list in turn.
We can add all the numbers in the list as follows:
applist( 0, LIST, nonop + ) ;;; nonop disables infix-ness of +
Oh? Did I say applist takes 2 arguments? Well, I did but don't forget
that Pop uses an open stack, so there's no notion of argument checking.
All the arguments go on the stack and come off again. This example works
because the iteration starts with 0 on the stack, then element 1 gets
pushed, then the top two items get added and replaced by the single result,
and so on and so on. At the end of the iteration, all that remains on
top of the stack is the answer.
Of course, the equivalent functional programming idiom (e.g. in Lisp)
would be to define a slightly different higher-order operator to
"applist" which might be called "fold".
define fold( sofar, list, op );
if null( list ) then
sofar
else
fold( op( sofar, hd( list ) ), tl( list ), op )
endif
enddefine;
That's always true. You can always do it in Lisp (or whatever) but
you just do it differently. Here's another nice use of the open stack.
Suppose we want to flatten a tree (represented as a list of lists)
into (say) a list. What's the idiomatic way of writing that? The answer
is to use the stack as a temporary collection zone.
define flatten_to_stack( tree );
if islist( tree ) then
applist( tree, flatten_to_stack )
else
tree
endif
enddefine;
define flatten( tree );
[% flatten_to_stack( tree ) %]
enddefine;
The virtue of writing flatten this way is that, for example, it might
turn out that we didn't want a list but we wanted a vector (1D array).
Well that was easy ...
define flatten( tree );
{% flatten_to_stack( tree ) %}
enddefine;
Changed my mind. I wanted to convert the vector into a string. Fine ...
define flatten( tree );
consstring(#| flatten_to_stack( tree ) |#)
enddefine;
Note the use of count brackets "#|" and "|#" in the above example. These
simply count the difference in the length of stack before and after the
expression between them. This makes sense when you know that consstring
expects a count of the number of characters on the stack as its "topmost"
argument.
This is probably far too long a post already but I could go on about the
open stack for another couple of hours. It is the most wonderful thing
about Pop and defines the language family. It is never the case that
it makes you able to do things that can't be done in Lisp-like
languages but it does make you want to say them rather differently!
Steve
|