On this page:
2.1 Detecting Symbolic Link Changes
filesystem/  link-change-evt
filesystem/  link-change-evt-cancel
filesystem/  link-change-evt?
2.2 Miscellaneous Utilities
2.3 Static Argument Checking
define/  check-args
define/  check-args/  contract
2.4 Structures
2.5 Extensions to find-executable-path
2.6 Development To-Do Expressions
TODO/  void
TODO/  scrbl
2.7 Testing Meta-Language
2.8 Extending require-provide

2 Unstable

 (require adjutor/unstable) package: adjutor

Unlike the preceding, features documented in this section are experimental and/or under development and are subject to breaking changes without notice.

I suggest that before using these features in production code you check with me about their status or, in the worst-case scenario, fork the library.

Changed in version 0.3 of package adjutor: Moved experimental things to adjutor/unstable to further clarify intent. Removed struct/derived in anticipation of Racket 7.6 (which will provide a struct/derived from racket/base) and removed the ill-considered delay/thread/eager-errors. Declared environment-variables-set* stable.

2.1 Detecting Symbolic Link Changes


(filesystem/link-change-evt path-string)

  path-string : path-string?


(filesystem/link-change-evt-cancel evt)  any

  evt : filesystem/link-change-evt?


(filesystem/link-change-evt? v)  any/c

  v : any/c
Similar to filesystem-change-evt, filesystem-change-evt-cancel, and filesystem-change-evt?, respectively, except that the events created by filesystem/link-change-evt become ready at additional times when path-string is a symbolic link (according to link-exists?).

Specifically, for symbolic links, filesystem change events detect changes on the target of the symbolic link, not on the link itself. In addition to detecting those changes, events created by filesystem/link-change-evt also become ready for synchronization when the link itself is deleted or changed to point to a different target (according to file-or-directory-identity).

Like filesystem change events, events created by filesystem/link-change-evt allocate resources at the operating-system level, which are placed in the custody of the current custodian. These resources are released automatically when the event is chosen for synchronization: otherwise, they must be released by shutting down the custodian via custodian-shutdown-all or by explicitly calling filesystem/link-change-evt-cancel. In either case, the event becomes ready for synchronization (if it is not already).

Note that these functions remain experimental. In particular, the desired behavior on Windows (where filesystem changes can be tracked only at directory-level resolution) has not been determined.

Added in version 0.2 of package adjutor.

2.2 Miscellaneous Utilities


(in-match val-expr maybe-bind-clause pat ...+)

maybe-bind-clause = 
  | #:bind [rslt-id ...]
A rather unusual form of sequence syntax. Using in-match creates a single-element, potentially-multi-valued sequence, somewhat like in-value*/expression, but its peculiar characteristics make it better thought of as a way of turning a for-clause into a binding form like match-let-values or match-define.

The maybe-bind-clause is mandatory unless in-match is used directly within a for-clause.

The val-expr is an expression, and each pat is a pattern for match: these are tried against the value of val-expr in the usual way. Each pat must bind every rslt-id, or an unbound identifier error will occur. The values of the sequence are those bound to the rslt-ids (in order) by the first pat which matches successfully.

Conceptually, the following sequences written using in-match and in-value*/expression are equivalent:
(in-match val-expr #:bind [rslt-id ...] pat ...+)
(let ([val val-expr])
   (match val
      (values rslt-id ...)]

Asside from brevity, the key advantage of in-match is that it installs the values of the rslt-ids based on their names, eliminating the requirement of getting them in the right order in every match clause, as one must with in-value*/expression.

As a special case, when in-match is used directly within a for-clause, the maybe-bind-clause may be omitted. Omitting the maybe-bind-clause is equivalent to using the same identifiers bound by the for-clause, so that the following are equivalent:
(for ([(rslt-id ...) (in-match val-expr
                               pat ...+)])
  for-body ...+)
(for ([(rslt-id ...) (in-match val-expr
                               #:bind [rslt-id ...]
                               pat ...+)])
  for-body ...+)

If the maybe-bind-clause is used inside a for-clause, it must bind the same number of values expected by the for-clause; otherwise, a syntax error is raised.

An in-match application can provide better performance when it appears directly in a for-clause (with or without a maybe-bind-clause).

> (for*/list ([spec `([3 4 5]
                      [10 20])]
              [(a b c) (in-match spec
                                 (list a b c)
                                 (list a (and b c)))])
    (+ a b c))

'(12 50)

> (for/list ([(x y) (in-match '(1 2)
                              #:bind [a b]
                              (list a b))])
    (+ x y))


> (for/first ([(x y) (in-match '(1 2)
                               (list x z))])
    (+ x y))

y: undefined;

 cannot reference an identifier before its definition

  in module: top-level


(multi subs ...+)

subs = sub-path
  | (sub-path ...)
sub-path = rel-string
  | id
Like multi-in, but for use with require-provide.

Added in version 0.1 of package adjutor.

2.3 Static Argument Checking


(define/check-args function-header body ...+)

Like the function form of define, but actually defines a macro that statically checks the number (and keywords) of arguments before expanding to an application of the underlying function. The function-header uses the same syntax as define (including curried functions, rest arguments, etc.), except that a plain identifier is dissalowed, as define/check-args must be able to determine the required arguments at compile time.

The resulting function can still be used as a first-class value, but checking only occurs for statically visible uses.

> (define/check-args (recur arg)
      [(pair? arg)
       (println (car arg))
       ; Oops! Forgot the arguments ...

eval:1.0: recur: too few by-position arguments

  at: ()

  within: (recur)

  in: (recur)


(define/check-args/contract function-header contract-expr body ...+)

  contract-expr : contract?
Like define/check-args, but the resulting function is additionally protected by the contract contract-expr. Unlike define/contract, blame is assigned to the module where the function is used (not necessarily the module where it is defined), facilitating the export of the identifier bound by define/check-args/contract.

2.4 Structures


(structure id maybe-super (field ...)
  option ...)
maybe-super = 
  | super-id
option = structure-option
  | restricted-struct-option
structure-option = #:constructor-contract contract-expr
  | #:constructor constructor-wrapper-expr
  | #:match-expander new-match-transformer
  contract-expr : contract?
  constructor-wrapper-expr : contract-expr
  new-match-transformer : (-> syntax? syntax?) ; in the transformer environment
In the simplest case, when no structure-options are given, defines a new structure type like struct, where a restricted-struct-option is any option that can be given to struct except for #:constructor-name, #:extra-constructor-name, #:name, and #:extra-name.

Any structure-options that are given control the meaning of id.

If a #:constructor option is given, the constructor-wrapper-expr is accessed instead of the default constructor when id is used as an expression. The constructor-wrapper-expr must satisfy the contract contract-expr if a #:constructor-contract option is given; otherwise, it is required to be a procedure. Inside the constructor-wrapper-expr, raw-constructor can be used to access the default constructor.

If a #:constructor-contract option is given without a #:constructor option, the default constructor is protected with the contract contract-expr.

If a #:match-expander clause is given, the new-match-transformer must be an expression in the transformer environment that produces a function from syntax to syntax. It is used instead of the default pattern-matching behavior when id is used as a match expander. Inside the new-match-transformer, raw-match-transformation can be used to implement transformers that expand to the default pattern-matching behavior.

As with struct, id can be used as a structure type transformer which can be used to define subtypes and cooperates with shared, struct-out, etc. (But note that a #:match-expander clause contols id’s cooperation with match.) For more detailed information about these uses of id, see Structure Type Transformer Binding.

Within a #:constructor clause of structure, accesses the plain constructor for the structure type. Illegal elsewhere.
Within a #:match-expander clause of structure, accesses a function that accepts a syntax object of the shape #'(_ pat ...) and returns syntax for match that matches each pat against the fields of the structure. Illegal elsewhere.

> (require (for-syntax racket/base syntax/parse))
> (structure point (x y z)
    #:constructor (λ ([x 0] [y 0] [z 0])
                    (raw-constructor x y z))
    #:constructor-contract (->* {}
                                {real? real? real?}
    #:match-expander (syntax-parser
                       [(_ x y z)
                        (raw-match-transformation #'(_ x y z))]
                       [(_ x y)
                        #'(point x y _)]
                       [(_ x)
                        #'(point x _ _)]
                        #'(point _ _ _)]))
> (match (point)
    [(point x) x])


> (struct-copy point (point 5)
               [z 42])

(point 5 0 42)

> (point #f)

point: contract violation

  expected: real?

  given: #f

  in: the 1st argument of

      (->* () (real? real? real?) point?)

  contract from: (definition point)

  blaming: top-level

   (assuming the contract is correct)

  at: eval:2.0

2.5 Extensions to find-executable-path

Racket provides find-executable-path for finding the paths of executables (or related files/directories) based on the PATH environment variable. However, in some cases programmers do not want to use the system-provided PATH.

In particular, on Mac OS, GUI programs are initialized with a very minimal PATH (at the time of writing, /usr/bin:/bin:/usr/sbin:/sbin), which prevents such programs from finding paths to most user-installed executables using find-executable-path unless the user takes special measures.

This library provides find-executable-path* and related bindings to address these cases at a higher level than manipulating environment variable sets directly.


(find-executable-path* program 
  #:search search-directories]) 
  (or/c path? #f)
  program : path-string?
  related : (or/c path-string? #f) = #f
  deepest? : any/c = #f
  search-directories : (listof path?)
   = (current-executable-search-directories)
Like find-executable-path, but searches based on search-directories rather than the value of (environment-variables-ref (current-environment-variables) #"PATH").


(current-executable-search-directories)  (listof path?)

(current-executable-search-directories search-directories)
  search-directories : (listof path?)
Specifies the list of directories to be searched by find-executable-path* when no #:search argument is provided. The default value is platform-specific.

On Mac OS, the default value is obtained by invoking Bash as a login shell, printing the PATH, and parsing the output. This allows the PATH to be modified by "~/.bash_profile", "/etc/paths", "/etc/paths.d/", etc. and is consistent with the behavior of "Terminal.app". Note that this behavior has not yet been tested on Mac OS Catalina.

On all other platforms, the default value is currently obtained by parsing the value of (environment-variables-ref (current-environment-variables) #"PATH") when adjutor/unstable is instantiated. On Windows, the default value begins with (bytes->path #".") for consistency with find-executable-path.

In the future, alternative ways of computing the default value may be supported.

2.6 Development To-Do Expressions


(TODO message)

(TODO #:expr runtime-expr message)
(TODO message #:expr runtime-expr)
message = msg-datum ...+ maybe-detail
maybe-detail = 
  | #: msg-datum ...+
The TODO form is intended to be used as a placeholder during development. When a runtime-expr is given, the entier form is equivalent to the runtime-expr being used directly. If there is no runtime-expr, evaluating the TODO form at runtime raises an error (based on the message).

If the todo-list plugin is installed (via the todo-list package), DrRacket will also highlight the placeholders specially.

A msg-datum is implicitly quoted and must me an literal string, symbol, or number. These are converted to strings with a " " added between them to form the message. If a maybe-detail part is given, it is omited from the summary view, for example.

Added in version 0.2.3 of package adjutor.


(TODO/void message)

Cooperates with DrRacket like TODO, but evaluates to #<void> at runtime.

Added in version 0.2.3 of package adjutor.


(TODO/scrbl [message] runtime-expr ...)

Cooperates with DrRacket like TODO, but designed when for use with the Scribble reader. Evaluates to (begin runtime-expr ...) at runtime.

Added in version 0.2.3 of package adjutor.

2.7 Testing Meta-Language

 #lang adjutor/unstable/test package: adjutor

The adjutor/unstable/test meta-language is useful for files that should only contain a test submodule. It chains to the following language like at-exp, then transforms the result of the other reader to place the body in a test submodule, leaving the enclosing module empty. It also arranges for a special #%top-interaction for the enclosing module so that the REPL is inside the test submodule.

To a first approximation, this is how a module using #lang adjutor/unstable/test is read compared to some host language:

#lang adjutor/unstable/test

Host Language


#lang adjutor/unstable/test lang-spec
body ...
#lang lang-spec
body ...


(module mod-name racket/base
  (module* test mod-lang
    body ...))
(module mod-name mod-lang
  body ...)

The main differences between the above table and the actual implementation of #lang adjutor/unstable/test are that a private module language is used instead of racket/base (to provide a useful #%top-interaction) and that a configure-runtime submodule is added.


(#%top-interaction . form)

The #%top-interaction installed for the enclosing module by #lang adjutor/unstable/test is configured to always enter! the test submodule before evaluating form.

2.8 Extending require-provide

The bindings in this section are provided for-syntax to be used in implementing extensions to require-provide. They are particularly experimental and subject to change.

A simple-require-provide-transformer contains a function proc (perhaps created syntax-parser) that specifies a simple macro-like rewrite rule. Like a macro, proc is called with the parenthesized form beginning with the identifier bound to the transformer itself. Its result must be a require-provide-spec.


(struct require-provide-transformer (proc))

  proc : 
(-> syntax?
    (values syntax? syntax?))
A require-provide-transformer is like a simple-require-provide-transformer, but more general. Its proc returns two syntax objects: the first must be a valid require-spec for use with require, and the second must be a provide-spec for use with provide.

syntax class


syntax class


Syntax classes recognizing the grammer for module paths and phase levels as specified by require and provide.

A syntax class recognizing the grammar documented under require-provide, including derived-require-provide-specs created with require-provide-transformer or simple-require-provide-transformer. It has two attributes require-stx and provide-stx, which are the syntax to be passed on to require and provide, respectively.