📄 optargs.scm
字号:
;;;; optargs.scm -- support for optional arguments;;;;;;;; Copyright (C) 1997, 1998, 1999, 2001 Free Software Foundation, Inc.;;;;;;;; This program is free software; you can redistribute it and/or modify;;;; it under the terms of the GNU General Public License as published by;;;; the Free Software Foundation; either version 2, or (at your option);;;; any later version.;;;;;;;; This program is distributed in the hope that it will be useful,;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the;;;; GNU General Public License for more details.;;;;;;;; You should have received a copy of the GNU General Public License;;;; along with this software; see the file COPYING. If not, write to;;;; the Free Software Foundation, Inc., 59 Temple Place, Suite 330,;;;; Boston, MA 02111-1307 USA;;;;;;;; As a special exception, the Free Software Foundation gives permission;;;; for additional uses of the text contained in its release of GUILE.;;;;;;;; The exception is that, if you link the GUILE library with other files;;;; to produce an executable, this does not by itself cause the;;;; resulting executable to be covered by the GNU General Public License.;;;; Your use of that executable is in no way restricted on account of;;;; linking the GUILE library code into it.;;;;;;;; This exception does not however invalidate any other reasons why;;;; the executable file might be covered by the GNU General Public License.;;;;;;;; This exception applies only to the code released by the;;;; Free Software Foundation under the name GUILE. If you copy;;;; code from other Free Software Foundation releases into a copy of;;;; GUILE, as the General Public License permits, the exception does;;;; not apply to the code that you add in this way. To avoid misleading;;;; anyone as to the status of such modified files, you must delete;;;; this exception notice from them.;;;;;;;; If you write modifications of your own for GUILE, it is your choice;;;; whether to permit this exception to apply to your modifications.;;;; If you do not wish that, delete this exception notice.;;;;;;;; Contributed by Maciej Stachowiak <mstachow@alum.mit.edu>;;; Commentary:;;; {Optional Arguments};;;;;; The C interface for creating Guile procedures has a very handy;;; "optional argument" feature. This module attempts to provide;;; similar functionality for procedures defined in Scheme with;;; a convenient and attractive syntax.;;;;;; exported macros are:;;; let-optional;;; let-optional*;;; let-keywords;;; let-keywords*;;; lambda*;;; define*;;; define*-public;;; defmacro*;;; defmacro*-public;;;;;;;;; Summary of the lambda* extended parameter list syntax (brackets;;; are used to indicate grouping only):;;;;;; ext-param-list ::= [identifier]* [#:optional [ext-var-decl]+]?;;; [#:key [ext-var-decl]+ [#:allow-other-keys]?]?;;; [[#:rest identifier]|[. identifier]]?;;;;;; ext-var-decl ::= identifier | ( identifier expression );;;;;; The characters `*', `+' and `?' are not to be taken literally; they;;; mean respectively, zero or more occurences, one or more occurences,;;; and one or zero occurences.;;;;;; Code:(define-module (ice-9 optargs) :export-syntax (let-optional let-optional* let-keywords let-keywords* define* lambda* define*-public defmacro* defmacro*-public));; let-optional rest-arg (binding ...) . body;; let-optional* rest-arg (binding ...) . body;; macros used to bind optional arguments;;;; These two macros give you an optional argument interface that is;; very "Schemey" and introduces no fancy syntax. They are compatible;; with the scsh macros of the same name, but are slightly;; extended. Each of binding may be of one of the forms <var> or;; (<var> <default-value>). rest-arg should be the rest-argument of;; the procedures these are used from. The items in rest-arg are;; sequentially bound to the variable namess are given. When rest-arg;; runs out, the remaining vars are bound either to the default values;; or to `#f' if no default value was specified. rest-arg remains;; bound to whatever may have been left of rest-arg.;;(defmacro let-optional (REST-ARG BINDINGS . BODY) (let-optional-template REST-ARG BINDINGS BODY 'let))(defmacro let-optional* (REST-ARG BINDINGS . BODY) (let-optional-template REST-ARG BINDINGS BODY 'let*));; let-keywords rest-arg allow-other-keys? (binding ...) . body;; let-keywords* rest-arg allow-other-keys? (binding ...) . body;; macros used to bind keyword arguments;;;; These macros pick out keyword arguments from rest-arg, but do not;; modify it. This is consistent at least with Common Lisp, which;; duplicates keyword args in the rest arg. More explanation of what;; keyword arguments in a lambda list look like can be found below in;; the documentation for lambda*. Bindings can have the same form as;; for let-optional. If allow-other-keys? is false, an error will be;; thrown if anything that looks like a keyword argument but does not;; match a known keyword parameter will result in an error.;;(defmacro let-keywords (REST-ARG ALLOW-OTHER-KEYS? BINDINGS . BODY) (let-keywords-template REST-ARG ALLOW-OTHER-KEYS? BINDINGS BODY 'let))(defmacro let-keywords* (REST-ARG ALLOW-OTHER-KEYS? BINDINGS . BODY) (let-keywords-template REST-ARG ALLOW-OTHER-KEYS? BINDINGS BODY 'let*));; some utility procedures for implementing the various let-forms.(define (let-o-k-template REST-ARG BINDINGS BODY let-type proc) (let ((bindings (map (lambda (x) (if (list? x) x (list x #f))) BINDINGS))) `(,let-type ,(map proc bindings) ,@BODY)))(define (let-optional-template REST-ARG BINDINGS BODY let-type) (if (null? BINDINGS) `(begin ,@BODY) (let-o-k-template REST-ARG BINDINGS BODY let-type (lambda (optional) `(,(car optional) (cond ((not (null? ,REST-ARG)) (let ((result (car ,REST-ARG))) ,(list 'set! REST-ARG `(cdr ,REST-ARG)) result)) (else ,(cadr optional))))))))(define (let-keywords-template REST-ARG ALLOW-OTHER-KEYS? BINDINGS BODY let-type) (if (null? BINDINGS) `(begin ,@BODY) (let* ((kb-list-gensym (gensym "kb:G")) (bindfilter (lambda (key) `(,(car key) (cond ((assq ',(car key) ,kb-list-gensym) => cdr) (else ,(cadr key))))))) `(let* ((ra->kbl ,rest-arg->keyword-binding-list) (,kb-list-gensym (ra->kbl ,REST-ARG ',(map (lambda (x) (symbol->keyword (if (pair? x) (car x) x))) BINDINGS) ,ALLOW-OTHER-KEYS?))) ,(let-o-k-template REST-ARG BINDINGS BODY let-type bindfilter)))))(define (rest-arg->keyword-binding-list rest-arg keywords allow-other-keys?) (if (null? rest-arg) '() (let loop ((first (car rest-arg)) (rest (cdr rest-arg)) (accum '())) (let ((next (lambda (a) (if (null? (cdr rest)) a (loop (cadr rest) (cddr rest) a))))) (if (keyword? first) (cond ((memq first keywords) (if (null? rest) (error "Keyword argument has no value.") (next (cons (cons (keyword->symbol first) (car rest)) accum)))) ((not allow-other-keys?) (error "Unknown keyword in arguments.")) (else (if (null? rest) accum (next accum)))) (if (null? rest) accum (loop (car rest) (cdr rest) accum)))))));; This is a reader extension to support the (deprecated) use of;; "#&optional" instead of "#:optional"(read-hash-extend #\& (lambda (c port) (issue-deprecation-warning "`#&' is deprecated, use `#:' instead.") (case (read port) ((optional) #:optional) ((key) #:key) ((rest) #:rest) ((allow-other-keys) #:allow-other-keys) (else (error "Bad #& value.")))));; lambda* args . body;; lambda extended for optional and keyword arguments;;;; lambda* creates a procedure that takes optional arguments. These;; are specified by putting them inside brackets at the end of the
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -