Re: How to Collect Sosofos?

Subject: Re: How to Collect Sosofos?
From: Dave Love <d.love@xxxxxxxx>
Date: 09 Sep 1997 18:34:52 +0100
>>>>> "Eliot" == W Eliot Kimber <eliot@xxxxxxxxxx> writes:

 Elliot> What I think I want to do is iterate over a node list 

I presume you don't mean a node-list type?  (Doesn't look so.)

 Elliot> and generate a bunch of sosfos (using make
 Elliot> formatting-instruction in this case).  My puzzle is how to
 Elliot> end the iteration and also return the appended sosofos.

Rule no. 1: Try to avoid explicit recursion.  Common patterns of
computation should be abstracted into higher-order functions (ones
that take functions as arguments).  This makes things re-usable and
more comprehensible (pace Richard Gabriel); if the abstractions are
primitives in the system the result will probably be more efficient
too.

There's a bunch of such functions defined on node-lists in the
standard; analogues for normal lists should follow through
replacements of functions like `node-list' by their normal list
equivalents like `cons' if necessary.

 Elliot> (define (process-props node
 Elliot>   (let ((propnames (split (node-property 'allpns node))))
 Elliot>     (sosofo-append 
 Elliot>       (let loop ((propnames propnames))
 Elliot>         (if (null? propnames)
 Elliot>           (what do I return here?)
 Elliot>           (sosofo-append
 Elliot>             (process-property (car propnames))
 Elliot>             (loop (cdr propnames))))))))

The inner `let' looks as though it wants to apply `process-property'
to each member of a list and append the resulting sosofos:
  (apply sosofo-append
         (map process-property propnames))
[`(apply <function> <list>)' corresponds to `(<function>
<list-element-1> <list-element-1> ...)'.]

 Elliot> What I can't figure out is what I return for the IF inside
 Elliot> the loop--my understanding is that the result of this loop
 Elliot> would always be the empty sosofo, not the sosofos appended by
 Elliot> the false branch.

Such recursions bottom out at some sort of `zero' or `unit' value _of
the appropriate type_, sometimes a useful clue `(empty-sosofo)' in
this case, by the looks of it.

 Elliot> I guess what I'm looking for is some kind of "for-each"
 Elliot> function that can return a list of sosofos

Here's a `map' -- unfortunately not in Jade -- though in this case
(iterating over a single list) the `map1' it contains is sufficient:
 (define (map f #!rest l)
   (let ((map1 (lambda (f l)
		 (let loop ((l l))
		   (if (null? l)
		       '()
		       (cons (f (car l))
			     (loop (cdr l))))))))
     (cond ((null? l)
	    '())
	   ((null? (cdr l))
	    (map1 f (car l)))
	   (else
	    (let loop ((l l))
	      (if (null? (car l))
		  '()
		  (cons (apply f (map1 car l))
			(loop (map1 cdr l)))))))))

 Elliot> or a way to accumulate sosofos explicitly.

See also `reduce'-like functions for combining elements of lists.

To test/understand things it's useful to have a system in which to
evaluate expressions interactively.  Presumbly DSC is a good choice
(I've not installed it), but the current versions of the Bigloo and
Gambit Scheme systems (see the comp.lang.scheme FAQ) understand the
DSSSL keyword and lambda syntax and could define a dummy lazy
node-list type, for instance.

After evaluating the above definition in Gambit from this Emacs buffer
I can test it and follow execution, perhaps even without having to
insert expressions to display local variables:

> (map + '(1 2) '(3 4))
(4 6)
> (trace +)
> (map + '(1 2) '(3 4))
|(+ 2 4)
|6
|(+ 1 3)
|4
(4 6)
> 

HTH.

-- 
 ``Abstraction, abstraction and abstraction.''
   This is the answer to the question ``What are the three most
   important words in programming?''   -- Paul Hudak

 DSSSList info and archive:  http://www.mulberrytech.com/dsssl/dssslist


Current Thread