Subject: Re: 3:rd solution sought
From: rpw3@rigden.engr.sgi.com (Rob Warnock)
Date: 1997/12/10
Newsgroups: comp.lang.scheme
Message-ID: <66lb8t$6pj2f@fido.asd.sgi.com>

Bengt Kleberg <bengtk@damek.kth.se> wrote:
+---------------
| Note that the real problem demands ... the use of (cons ..) in the
| construction of the _list_ of results. Ie, don't use an accumulator to
| make that part of the code tail-recursive. As you can see it is ok to use
| an accumulator for _one_ of the results.
| The toy example: Given a list '( 1 1 1 0 1 1 1 1 1 0 1 1 1 0 1 1 0) I want
| to get a result like this '(3 5 3 2). Ie, add the ones until you reach a 0,
| then start anew.
+---------------

Interesting coincidence! Just last night I had occasion to write some code
(as part of a small assembler for a weird RISC) that does something almost
identical, except the sub-results needed to be lists, too. That is, assuming
"0" is the magic delimiter and given a list '(1 2 3 0 5 0 5 2 1), return
((1 2 3) (5) (5 2 1)).  My solution was one tail-recursive routine, inside
a driver that special-cased null input:

  (define MAGIC-TOKEN 0)                      ; or whatever
  (define (DELIM-TEST x) (eq? x MAGIC-TOKEN)) ; or equal? or whatever

  (define (gather-between-delims ls)
    (letrec ((gather
	       (lambda (result partial input)
		 (cond
		   ((null? input)
		    (reverse (cons (reverse partial) result)))
		   ((DELIM-TEST (car input))
		    (gather (cons (reverse partial) result) '() (cdr input)))
		   (else
		    (gather result (cons (car input) partial) (cdr input)))))))
      (if (null? ls)
	ls
	(gather '() '() ls))))

Examples:

  (gather-between-delims '(1 2 3 0 5 0 4 2 1))
   ==> ((1 2 3) (5) (4 2 1))

  (gather-between-delims '(1 1 1 0 1 1 1 1 1 0 1 1 1 0 1 1 0))
   ==> ((1 1 1) (1 1 1 1 1) (1 1 1) (1 1) ())

You can get Kleberg's "summation" result with:

  (map length (gather-between-delims '(1 1 1 0 1 1 1 1 1 0 1 1 1 0 1 1 0)))
   ==> (3 5 3 2 0)

Though note that I deliberately chose not to suppress the empty list/count
at the end, since it was significant in my application.


-Rob

p.s. You can see what I was using it for if you replace "0" with ",",
and replace single-digit numbers with various other tokens (and add
a lexer to produce them):

  (define MAGIC-TOKEN #\,)

  (gather-between-delims
    (cdr (tokenize-string "addi t3,a0+1,tbl_end-tbl_beg+1)))
  ==> ((t3) (a0 #\+ 1) (tbl_end #\- tbl_beg #\+ 1))

Now all I need is to map a simple "infix->prefix" over that, and:

  ==> (t3 (+ a0 1) (+ (- tbl_end tbl_beg) 1))

-----
Rob Warnock, 7L-551		rpw3@sgi.com   http://reality.sgi.com/rpw3/
Silicon Graphics, Inc.		Phone: 650-933-1673 [New area code!]
2011 N. Shoreline Blvd.		FAX: 650-933-4392
Mountain View, CA  94043	PP-ASEL-IA