dotlambda/scribblings/dotlambda.scrbl

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.}