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.

Reply via email to