This is the mail archive of the guile@cygnus.com mailing list for the guile project.
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |
With all this discussion on optional arguments handlers, has anyone looked at the let-optionals macros used in scsh (let-opt.scm)? They're implemented in Clinger/Rees high level macros and handle optional arguments in a very schemely manner. Here's some of the doc from that file. I ported these to defmacro at one point for a scsh port to Gambit, it's not hard. ;;; (LET-OPTIONALS arg-list ((var1 default1) ...) ;;; body ;;; ...) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; This form is for binding a procedure's optional arguments to either ;;; the passed-in values or a default. ;;; ;;; The expression takes a rest list ARG-LIST and binds the VARi to ;;; the elements of the rest list. When there are no more elements, then ;;; the remaining VARi are bound to their corresponding DEFAULTi values. ;;; It is an error if there are more args than variables. ;;; ;;; - The default expressions are *not* evaluated unless needed. ;;; ;;; - When evaluated, the default expressions are carried out in the *outer* ;;; environment. That is, the DEFAULTi forms do *not* see any of the VARi ;;; bindings. ;;; ;;; I originally wanted to have the DEFAULTi forms get eval'd in a LET* ;;; style scope -- DEFAULT3 would see VAR1 and VAR2, etc. But this is ;;; impossible to implement without side effects or redundant conditional ;;; tests. If I drop this requirement, I can use the efficient expansion ;;; shown below. If you need LET* scope, use the less-efficient ;;; LET-OPTIONALS* form defined below. ;;; ;;; Example: ;;; (define (read-string! str . maybe-args) ;;; (let-optionals maybe-args ((port (current-input-port)) ;;; (start 0) ;;; (end (string-length str))) ;;; ...)) ;;; ;;; expands to: ;;; ;;; (let* ((body (lambda (port start end) ...)) ;;; (end-def (lambda (%port %start) (body %port %start <end-default>))) ;;; (start-def (lambda (%port) (end-def %port <start-default>))) ;;; (port-def (lambda () (start-def <port-def>)))) ;;; (if (null? rest) (port-def) ;;; (let ((%port (car rest)) ;;; (rest (cdr rest))) ;;; (if (null? rest) (start-def %port) ;;; (let ((%start (car rest)) ;;; (rest (cdr rest))) ;;; (if (null? rest) (end-def %port %start) ;;; (let ((%end (car rest)) ;;; (rest (cdr rest))) ;;; (if (null? rest) (body %port %start %end) ;;; (error ...))))))))) ;;; (:optional rest-arg default-exp) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; This form is for evaluating optional arguments and their defaults ;;; in simple procedures that take a *single* optional argument. It is ;;; a macro so that the default will not be computed unless it is needed. ;;; ;;; REST-ARG is a rest list from a lambda -- e.g., R in ;;; (lambda (a b . r) ...) ;;; - If REST-ARG has 0 elements, evaluate DEFAULT-EXP and return that. ;;; - If REST-ARG has 1 element, return that element. ;;; - If REST-ARG has >1 element, error. ;;; (LET-OPTIONALS* args ((var1 default1) ... [rest]) body1 ...) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; This is just like LET-OPTIONALS, except that the DEFAULTi forms ;;; are evaluated in a LET*-style environment. That is, DEFAULT3 is evaluated ;;; within the scope of VAR1 and VAR2, and so forth.