[plt-scheme] keyword arguments (in v4.0, maybe)

From: Eli Barzilay (eli at barzilay.org)
Date: Tue Jun 12 13:12:04 EDT 2007

On Jun 12, Matthew Flatt wrote:
> So probably `procedure?' should return #f for things that are like
> procedures, but that require some keyword (as opposed to things that
> work like procedures and accept keyword-based arguments, but all the
> keyword arguments all optional). Then, the above remains true for
> procedures.
> Meanwhile, it's true that there's a kind of infection to the design,
> in that many tools and libraries should be made to work with both
> procedures and keyword-requiring things. But maybe working only for
> procedures (that don't require any keywords) is a reasonable
> specification for other tools and libraries.
> What examples do we have, other than `trace'?

I grepped the PLT tree for other examples.  This is a summary of
things I found.  (Some of these don't apply, some might apply in the
future.  I'm just trying to provide a quick overview, not a proper

* Definitions like
    (define (oprintf . args) (apply fprintf o args))
  would need to change if `fprintf' is extended (even if kwds are
  optional, since the intention is to have `oprintf' be the same as
  `fprintf').  I can see several additional builtin candidates for
  keywords.  (The infection-aspect of this is visible in that after
  the above extension, uses of this `oprintf' in `apply' will need to
  be extended too.)

  Completely new languages (like frtime, lazy, typed scheme, the new
  servlet language) will probably need to use keyword wrappers in many
  places too.

* There is another aspect to this problem -- back when we were
  discussing keyword arguments, one important feature I talked about
  is that they should make it easy to extend an existing definition in
  a way that does not require changing all call sites.  The change in
  `apply' violates this -- if you extend `fprintf' with keywords, you
  will have to inspect and possibly modify all uses of it in `apply'.
  And BTW, it doesn't help that you're looking for uses that involve
  `apply' only -- since you don't know how values move around.

* A popular use of wrappers is in testing code.

* The foreign interface uses function wrappers for custom C types (but
  does not use `apply').  Related: `do-fit' from
  "plot/fit-low-level.ss" applies a provided callback.  Also things
  like "ffi/esd.ss" use apply for similar reasons.

* FrTime has `(apply apply fn args)' in several places.  There is a
  similar thing in "plot/fit.ss".

* `ext:wrap' from "web-server/private/response.ss"

* "make/setup-extension.ss" -- applies a given setup hook.

* handin-server/private/reloadable.ss -- installs a function wrapper
  for auto-reloading code; .../private/run-status.ss -- applies a
  messenger value (taken from a parameter); .../utils.ss applies a
  checker procedure.

* lazy/force.ss uses a wrapper when doing a "very deep" (!!!) force of
  a value -- wraps functions so their results is forced.

* In class code, (apply super-init args) is often used (not a problem
  while class initialization uses it's own keyword mechanism, which I
  think would be nice to change eventually).  Same goes for a future
  extension of `make-object' and `struct-type-make-constructor'.

* "web-server/web-server.ss" has code that calls a bunch of
  callbacks+args -- `(for-each apply shutdowns)'

* `control-io-apply' from "setup/setup-unit.ss"

* "compiler/private/xform.ss" has some printf-wrappers, and some
  trace-like wrappers.

* `make-closure-definition-syntax' from "web-server/private/closure.ss"

* `make-shared-array' from "srfi/63/63.ss" applies a provided `mapper'

* "srfi/25/arlib.scm" (and others) has a few mapping functions for

* `run' from "preprocessor/pp-run.ss" applies a given preprocessor

* "compiler/src2src.ss" applies an arbitrary mzscheme function for
  constant folding

* `tree-apply' from "planet/private/planet-shared.ss"

* `mk-k' from "eopl/eopl.ss"; `sllgen:apply-reduction' from

* `output-form' from "swindle/html.ss" wraps a function for formatted
  output, and the same uses lots of wrapping for a hierarchy of html
  tag functions

* "swindle/misc.ss" defines `memoize'

* "swindle/base.ss" redefines `#%app' so `(foo x . r)' is the same as
  `(apply foo x r)' -- this was one of my first hack that were only
  because I was excited by the new module/syntax system.  As
  questionable as this is, it means that it's even more difficult to
  find problematic code.

* "swindle/tiny-clos.ss" uses *lots* of `apply's for invoking
  generics, slot access, etc etc etc.

* "swindle/misc.ss" defines `map!', `mappend', `mappend!', `mapply',
  `some', `every',

* `for-each-snip' and `map-snip' from

* "srfi/1/..." defines `any', `every', `list-index', `count', `fold',
  `fold-right', `pair-fold-right', `pair-fold', `reduce',
  `reduce-right', `append-map', `append-map!', `pair-for-each',
  `map!', `filter-map', `my-map', `my-for-each'

* "mzlib/list.ss" defines `foldl', `foldr'

* "mzlib/etc.ss" defines `compose'

* `consumer-thread' from "mzlib/thread.ss"

* `define-macro' from "mzlib/defmacro.ss"

* `default-sandbox-guard' wraps `(sandbox-network-guard)' to make that
  function customizable (in "mzlib/sandbox.ss")

OK, I'm tired of this...

On Jun 12, Matthew Flatt wrote:
> > What would the expansion look like?
> The expression
>  (lambda (x #:y y) (list x y))
> would expand to something like
>   (make-keyword-procedure-with-info
>     (lambda (kws x) (list a (cdar kws)))
>     '(#:y) ; required
>     '())   ; optional
> The expression
>   (f 1 #:y 2)
> would expand to something like
>  (let ([r f]
>        [a1 1]
>        [a2 2])
>    (keyword-apply r (list (cons #:y a2)) a1))

Ooh, lots of consing...  More in a followup message.

          ((lambda (x) (x x)) (lambda (x) (x x)))          Eli Barzilay:
                  http://www.barzilay.org/                 Maze is Life!

Posted on the users mailing list.