Comments on SRFI-1. Shriram Krishnamurthi 04 Jan 1999 15:41 UTC

Harvey J. Stein wrote:

> I. Function addition - list-length>=?
> First of all, I'd like to suggest adding a function.  I often find
> myself having to write code like:
>    (if (>= (length l) 3)
>        (do something with (list-ref l 2)))
> I guess this sometimes comes from processing the rest variable in
> funtions defined like (lambda (x y . rest) ...), but it also arises in
> other contexts.
> This has the ugly performance of hit that it takes O((length l))
> instead of O(position being tested).
> So, may I suggest adding:
>    list-length>=? l n -> #t/#f
>    Returns #t iff (>= (length l) n)
> This has the obvious implementation:
>    (define (list-length>=? l n)
>       (if (<= n 0)
>           0
>           (list-length>=? (cdr l) (- n 1))))

1. The "obvious implementation" doesn't at all seem to correspond with
the functionality you want.  But that's easy enough to fix.

2. This seems like exactly the sort of thing exceptions are designed
to get around.  You should be able to write

  (let ((name (list-ref argument-list 3)))

expecting that there are four values in `argument-list'; if there
aren't, you can handle the ensuing exception as you deem appropriate
(eg, locally if you want to provide a default value, or globally if
you want to signal an error and exit).  That's probably what you
_mean_ to say, anyway.

3. This procedure is anyway "inefficient" in that its client will
almost certainly traverse the same n elements again.  (Dan Friedman
would say that it "leaks computation".)  So it would be better off
taking a one-argument procedure that takes the remainder of the list
and uses it appropriately.  Better still, then, take two arguments,
the second being the failure continuation (which would be invoked in
tail position wrt the original calling context).  Or, you could
generalize this to

  list-split: int x list x (list -> beta) x (list -> gamma) x
              (() -> delta) -> (beta + gamma)

This is similar to, but not identical to, `partition'.  To be closer
to the spirit of partition, we could define

  list-split: int x list -> [list list]

(for which I don't see an equivalent in the proposal).

Here's a (lightly-tested) implementation:

(define (list-split n l)
  (define (helper index before after)
      ((null? after) (error 'list-split
		       "list ~s too small to be split at position ~s"
		       l n))
      ((= index 0) (values (reverse before) after))
      (else (helper (sub1 index) (cons (car after) before) (cdr after)))))
    ((< n 0) (error 'list-split "index ~s must be >= 0" n))
    (else (helper n '() l))))

(A better name might be list-split-at-nth or some such.)

If you want just the tail and not the head, then `list-tail' already
does exactly what you want (and returns the rest of the list to boot,
so you can just take the car of the result to get the n'th value).