85 lines
4.4 KiB
Racket
85 lines
4.4 KiB
Racket
#lang scribble/manual
|
|
@require[@for-label[@only-in[dotlambda #%dot-separator #%dotted-id]
|
|
racket/stxparam]]
|
|
|
|
@title{Dotted identifiers and @racket[λ<arg>.code] syntax}
|
|
@author[@author+email["Georges Dupéron" "georges.duperon@gmail.com"]]
|
|
|
|
@(begin
|
|
(module orig racket/base
|
|
(require scribble/manual
|
|
typed/racket/base)
|
|
(provide orig:#%module-begin)
|
|
(define orig:#%module-begin (racket #%module-begin)))
|
|
(require 'orig))
|
|
|
|
@defmodulelang[dotlambda]{
|
|
This @hash-lang[] language overrides @orig:#%module-begin from
|
|
@racketmodname[typed/racket/base], and splits identifiers which contain dots,
|
|
following these rules:
|
|
@itemlist[
|
|
@item{A single dot splits the identifier, and the dot is replaced with
|
|
@racket[#%dot-separator]. If an identifier is split by one or more
|
|
non-consecutive dots, all the resulting identifiers, including the
|
|
occurrences @racket[#%dot-separator] are placed in a syntax list, starting
|
|
with @racket[#%dotted-id], so that @racket[a.b.c] gets transformed into
|
|
@racket[(#%dotted-id a #%dot-separator b #%dot-separator c)].}
|
|
@item{A leading dot (which is not followed by another dot) is allowed, and is
|
|
replaced with @racket[#%dot-separator], like dots occurring in the middle of
|
|
the identifier.}
|
|
@item{A dot immediately preceded or followed by an ellipsis @racket[…] can be
|
|
omitted, so that @racket[a.….b], @racket[a….b], @racket[a.…b] and
|
|
@racket[a…b] are all translated to
|
|
@racket[(#%dotted-id a #%dot-separator … #%dot-separator b)].}
|
|
@item{Two or more dots do not split the identifier, but one of the dots is
|
|
removed (i.e. it escapes the other dots).}
|
|
@item{If an identifier ends with a dot, a single trailing dot is removed and
|
|
the identifier is otherwise left intact (i.e. the trailing dot escapes the
|
|
whole identifier).}
|
|
@item{Identifiers consisting only of dots are left unchanged, as well as the
|
|
following: @racket[..+], @racket[...+], @racket[..*], @racket[...*],
|
|
@racket[…], @racket[…+], @racket[…*] and @racket[::...].}]
|
|
|
|
Furthermore the syntax @racket[λarg₁.arg₂.….argₙ.(expr …)] is recognised as a
|
|
shorthand for @racket[(λ (arg₁ arg₂ … argₙ) (expr …))], so that
|
|
@racket[λx.(+ x 2)] is roughly translated to @racket[(λ (x) (+ x 2))]. If the
|
|
@racket[_var] part is left empty, then it defaults to @racket[%1], @racket[%2]
|
|
and so on. The number of parameters is determined from the syntactical
|
|
contents of the function's body, before performing macro-expansion. The term
|
|
@racket[λ.(+ %1 %2)] is therefore roughly translated to
|
|
@racket[(λ (%1 %2) (+ %1 %2))]. The variable named @racket[%] can be used as a
|
|
shorthand for @racket[%1], so that @racket[λ.(+ % 10)] is therefore roughly
|
|
translated to @racket[(λ (%) (+ % 10))].
|
|
|
|
Since this substitution is performed on the whole program, before
|
|
macro-expansion, these notations are performed regardless of the context in
|
|
which an expression occurs. For example, the quoted term @racket['a.b] will
|
|
also get translated to @racket['(#%dotted-id a #%dot-separator b)]. In this
|
|
way, the @racket[#%module-begin] from @racket[dotlambda] works a bit like if
|
|
it were a reader extension.
|
|
|
|
@bold{Warning:} There probably are some issues with hygiene, especially in
|
|
mixed contexts (e.g. literate programs, or typed/racket programs with untyped
|
|
code at phase 1). I will think about these issues and adjust the behaviour in
|
|
future versions. Future versions may therefore not be 100% backward-compatible
|
|
with the current version, but the general syntax of dotted identifiers should
|
|
hopefully not change much.}
|
|
|
|
@defform[#:kind "syntax parameter"
|
|
(#%dotted-id ids-and-separators …)]{
|
|
The default implementation currently translates @racket[a.b.c.d] to
|
|
@racket[(d (c (b a)))], and @racket[.a.b.c] to
|
|
@racket[(λ (x) (c (b (a x))))].
|
|
|
|
This behaviour can be altered using @racket[syntax-parameterize]. I don't
|
|
think syntax parameters can be modified globally for the whole containing file
|
|
like parameters can (via @racket[(param new-value)]), so the exact mechanism
|
|
used to customise the behaviour of @racket[#%dotted-id] may change in the
|
|
future.}
|
|
|
|
@defidform[#%dot-separator]{
|
|
Indicates the presence of a (possibly implicit) dot. The original string
|
|
(usually @racket["."] or the empty string @racket[""] for an implicit dot
|
|
before or after an ellipsis) is normally stored in the
|
|
@racket['dotted-original-chars] syntax property of the occurrence of the
|
|
@racket[#%dot-separator] identifier.} |