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
procedure
(filesystem/link-change-evt path-string)
→ filesystem/link-change-evt? path-string : path-string?
procedure
(filesystem/link-change-evt-cancel evt) → any
evt : filesystem/link-change-evt?
procedure
v : any/c
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
syntax
(in-match val-expr maybe-bind-clause pat ...+)
maybe-bind-clause =
| #:bind [rslt-id ...]
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.
(in-match val-expr #:bind [rslt-id ...] pat ...+) (let ([val val-expr]) (in-value*/expression (match val [pat (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.
(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)) '(3)
> (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
syntax
(multi subs ...+)
subs = sub-path | (sub-path ...) sub-path = rel-string | id
Added in version 0.1 of package adjutor.
2.3 Static Argument Checking
syntax
(define/check-args function-header body ...+)
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) (cond [(pair? arg) (println (car arg)) ; Oops! Forgot the arguments ... (recur)] [else arg])) eval:1:0: recur: too few by-position arguments or expected
more terms
at: ()
within: (recur)
in: (recur)
syntax
(define/check-args/contract function-header contract-expr body ...+)
contract-expr : contract?
2.4 Structures
syntax
(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
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.
syntax
Within a #:constructor clause of structure, accesses the plain constructor for the structure type. Illegal elsewhere.
syntax
> (require (for-syntax racket/base syntax/parse))
> (structure point (x y z) #:transparent #:constructor (λ ([x 0] [y 0] [z 0]) (raw-constructor x y z)) #:constructor-contract (->* {} {real? real? real?} point?) #: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]) 0
> (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.
procedure
(find-executable-path* program [ related deepest? #: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)
parameter
(current-executable-search-directories search-directories) → void? search-directories : (listof path?)
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
syntax
(TODO message)
(TODO #:expr runtime-expr message) (TODO message #:expr runtime-expr)
message = msg-datum ...+ maybe-detail maybe-detail =
| #: msg-datum ...+
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.
syntax
(TODO/void message)
Added in version 0.2.3 of package adjutor.
syntax
(TODO/scrbl [message] runtime-expr ...)
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:
Host Language | |||||||
Source |
|
| |||||
Parsed |
|
|
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.
syntax
(#%top-interaction . 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.
struct
(struct simple-require-provide-transformer (proc))
proc : (-> syntax? syntax?)
syntax class
syntax class
syntax class