home *** CD-ROM | disk | FTP | other *** search
- From: sfk@otter.hpl.hp.com (Steve Knight)
- Date: Wed, 18 Nov 1992 12:29:21 GMT
- Subject: Re: A little Pop history
- Message-ID: <116670012@otter.hpl.hp.com>
- Organization: Hewlett-Packard Laboratories, Bristol, UK.
- Path: sparky!uunet!charon.amdahl.com!pacbell.com!sgiblab!sdd.hp.com!hpscit.sc.hp.com!scd.hp.com!hpscdm!hplextra!otter.hpl.hp.com!otter!sfk
- Newsgroups: comp.lang.pop
- References: <Bxpqvt.Lq@deshaw.com>
- Lines: 118
-
- Nice to hear from Jonathan again. So as a greeting I'll stick the boot
- in on his implementation of recursivemember :-)
-
- Jonathan implements recursivemember like this:
- > define recursivemember(item, list);
- > var item, list, element;
- > if list = [] then
- > return(false)
- > endif;
- > for el in list do
- > if el = item then
- > return(true)
- > elseif islist(el) and recursivemember(item, el) then
- > return(true);
- > endif
- > endfor;
- > return(false);
- > enddefine;
-
- I still don't much like this as a solution. For example, you can never
- find [] in a tree -- but you can find all other lists. We need to take
- a systematic view of the meaning of lists representing tress. We can
- either adopt the view that the trees are built up from "dotted pairs", to
- borrow Lisp-speak, or that the lists simply represent linear
- collections.
-
- The first view leads to this solution. But look how horribly [] gets
- treated again.
-
- define recmem( x, tree );
- x = tree or
- tree.islist and not( tree.null ) and
- ( recmem( x, tree.hd) or recmem( x, tree.tl ) )
- enddefine;
-
- Ikk. The more typical Pop-style solution is to treat the lists as being
- linear collections rather than binary trees. This gives us the following
- solution
-
- define recmem( x, tree );
-
- define recmemlist( x, list );
- not( list.null ) and
- ( recmem( x, list.hd ) or recmemlist( x, list.tl )
- enddefine;
-
- x = tree or tree.islist and recmemlist( x, tree )
- enddefine;
-
- This is obviously an inefficient solution -- it chews up stack space
- like there is no tomorrow, because no implementation of Pop does
- tail-call optimisation. So you need to modify the solution like this
-
- define recmem( x, tree );
-
- define recmemlist( x, list );
- not( list.null ) and
- ( recmem( x, list.hd ) or chain( x, list.tl, recmemlist ) )
- enddefine;
-
- x = tree or tree.islist and chain( x, tree, recmemlist )
- enddefine;
-
- The call to "chain" forces the currently active procedure to exit and
- invoke the procedure on top of the stack. In other words this is a manual
- implementation of tail-call optimisation.
-
- As an alternative, you might choose to expand the recursion into a
- loop. But that's a detail and there would be only a minor
- performance gain. And you would use up more stack space. So take
- your pick. Here's the above routine converted to use a loop.
-
- define recmem( x, tree );
- x = tree or
- tree.islist and
- lblock ;;; begin new lexical block.
- lvars result = false; ;;; tree might be null.
- until tree.null do
- ;;; Nice Pop idiom. "dest" returns head and tail of a
- ;;; non-empty list. So E.dest -> E is an expression that
- ;;; steps E down the list and leaves the head on the stack.
- recmem( x, tree.dest -> tree ) -> result;
- quitif( result ); ;;; shortcut when we find true.
- enduntil;
- result ;;; push the result.
- endlblock
- enddefine;
-
- Since this version was created from the recursive version, it retains all
- the behaviour we want. In particular, it treats [] as a legitimate search
- target and doesn't make it a special case. One criticism, however, would
- be that the algorithm doesn't immediately generalise to a representation
- of trees as vectors (1D arrays).
-
- To remedy that, we can introduce the appropriate for loop:
-
- define recmem( x, tree );
- x = tree or
- x.isvector and
- lblock
- lvars result = false;
- for i in_vector tree do
- ;;; Another cute idiom. ->> is an assignment that duplicates
- ;;; the value on the stack before the assignment.
- quitif( recmem( x, t ) ->> result )
- endfor;
- result
- endlblock
- enddefine;
-
- This version can be trivially modified to cope with any data type
- that provides a loop or iteration procedure. It has no special treatment
- for any element. It is efficient in both space and time, although not
- quite optimal in either. And a mere 11 lines of non-commented code.
-
- Yow!
-
- Steve
-