On Sat, Aug 4, 2018 at 5:26 AM, George Neuner <gneun...@comcast.net> wrote:
> On Sat, 4 Aug 2018 00:08:46 -0500, Philip McGrath > <phi...@philipmcgrath.com> wrote: > > >You can call a function with dynamically calculated keyword arguments > using > >keyword-apply > ><http://docs.racket-lang.org/reference/procedures.html?q= > keyword-apply#%28def._%28%28lib._racket%2Fprivate% > 2Fbase..rkt%29._keyword-apply%29%29>, > > But the called function has to accept the keyword(s) passed. The > issue would seem to be defining functions without using keyword > literals. > This is true of the built-in `keyword-apply`, but using other parts of the API, particularly `procedure-keywords`, you can dynamically determine what keywords some function accepts and filter out extraneous ones, either in a new `keyword-apply`-like function or in a wrapper for the original function. Either the library author or a client can do this without special cooperation from the other. > >and you can create a function that accepts arbitrary or > >dynamically-calculated keyword arguments (which is rarely desirable) using > >make-keyword-procedure > > But this creates a procedure that accepts anything. This seems worse > than the solution using the plist: the keyword accepting variant of > the function can't have named positional arguments. > Actually, the function passed to `make-keyword-procedure` can have required and/or optional named positional arguments. You can use `procedure-reduce-keyword-arity` to further specialize what arguments the resulting function requires and/or accepts. Racket's built-in keyword argument system is fully dynamic (though admittedly not always convenient to use dynamically out of the box), but it also provides great support for the common case where the keywords to be applied are statically visible, which an ad-hoc symbols-as-"keywords" system can't. I've included some examples of working dynamically with keyword functions. I'm still not sure if this addresses Sanjeev's question, though: he asked about "a similar #:unless cause for a bunch of for expressions", which is a completely different use of syntactic keywords. #lang racket (define (keyword-apply-accepted proc kws kw-args by-pos-args) (define-values (required-kws accepted-kws/false) (procedure-keywords proc)) (define-values (kws* kw-args*) (cond [(list? accepted-kws/false) (for/lists (kws* kw-args*) ([kw (in-list kws)] [arg (in-list kw-args)] #:when (memq kw accepted-kws/false)) (values kw arg))] [else ;; -> proc already accepts any keyword (values kws kw-args)])) (keyword-apply proc kws* kw-args* by-pos-args)) (define (add x #:base [base 0]) (+ x base)) ;; Returns 1: (keyword-apply-accepted add '(#:dynamic-kw) '(ignored) '(1)) (define add/show ;; accepts exactly one named positional argument (make-keyword-procedure (λ (kws kw-args x) (printf "Given Keywords:\n") (for ([kw (in-list kws)] [arg (in-list kw-args)]) (printf " ~v ~v\n" kw arg)) (keyword-apply-accepted add kws kw-args (list x))) add)) ;; Returns 1: (add/show #:ignored "any value" 1) ;; Returns 3: (add/show 1 #:base 2 #:other "also ignored") (define add/show/base-required ;; Like add/show, but #:base is required (procedure-reduce-keyword-arity add/show (procedure-arity add/show) '(#:base) #f)) ;; Raises an exception: (add/show/base-required 42) -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.