As we all know ideas build up over time and turn into things we didn't initially imagine. In my case I started with a basic function that I used that was simple and useful and it has recently grown into something more useful. First, the code:
(define (length? lst (n 1)(op =) booltest)
(and (op (length lst)
(if (or (string? n)(list? n))(length n) n))
(if booltest
(if (list? booltest)
(for-all true?
(map for-all booltest (dup lst (length booltest))))
(for-all booltest lst))
true
)))
We often want to see if a list's number of arguments fits within a certain range and whether all of its members satisfy some criteria. Now we can test for both with the length? function. The length? function takes a list as argument and optionally can include an integer to test the length against, a comparison operator and a boolean test function to do a for-all comparison on the list. If all conditions are satisfied then true is returned. The test defaults to 1 and the comparison operator defaults to =. Here are some examples of how this works:
(length? lst) - does the list have 1 element?
(length? lst 2) - does the list have 2 elements?
(length? lst 3 >) - does the list have more than 3 elements?
(length? lst 3 = integer?) - do we have a list of 3 integers?
(length? lst 3 = (list integer? zero?)) - do we have a list of 3 integers that are 0?
That is pretty neat but there is more! If we have another list instead of a comparison number we can use a comparison operator to see how the number of arguments compare with one another. In this case we can only use <, = and > as comparators. Here are some more examples of how this works:
(length? lst1 lst2) - are the lists of equal length?
(length? lst1 lst2 >) - does lst1 have more arguments than lst2?
(length? lst1 lst2 <) - does lst1 have fewer arguments than lst2?
Of course one can compare string lengths this way as well. I think it is clear that this makes life much easier. Here is an example of how one could use the function in a practical way. The integer-vector? function determines if its input is a non-zero length list of integers.
(define (integer-vector? v)(length? v 0 > integer?))
So let the votes begin, should this be a new function in the language? Can it be generalized even more?
Here is yet another enhancement I have recently added. We can now compare the lengths of two lists. So the expression
(length? list-1 list-2) returns true if the two lists are equal in length or one can add a comparison operator. For instance,
(length? list-1 list-2 <) returns true if the length of list-1 is less than the length of list-2. Here is the new code:
(define (string-or-list? x)(or (list? x)(string? x)))
(define-macro (length?)
(let (len (length (args))
fst (eval (args 0))
scd (eval (args 1))
)
;....if we have two lists to compare
(if (and (<= 2 len 3)
(string-or-list? fst)
(string-or-list? scd))
((if (= len 2) = (eval (args 2)))
(length fst)
(length scd))
;....otherwise operate on a single list
(apply length2? (map eval (args)))
)
)
)
(define (length2? lst (n 1)(op =) booltest)
(and (op (length lst)
(if (string-or-list? n)(length n) n))
(if booltest
(if (list? booltest)
(for-all true?
(map for-all booltest (dup lst (length booltest))))
(for-all booltest lst))
true
)))