Beautiful Racket @link["http://beautifulracket.com"]{is a book} about making programming languages with Racket.
@defmodule[br]
@link["http://beautifulracket.com"]{@italic{Beautiful Racket}} is a book about making programming languages with Racket.
This library provides the @tt{#lang br} teaching language used in the book, as well as supporting modules that can be used in other programs.
This library is designed to smooth over some of the small idiosyncrasies and inconsistencies in Racket, so that those new to Racket are more likely to say ``ah, that makes sense'' rather than ``huh? what?''
@;defmodulelang[br]
@defmodule[br]
@section{The @tt{br} language(s)}
@defmodulelang[br]
@defmodulelang[br/quicklang]
@tt{#lang br} is a teaching language designed to smooth over some of the small idiosyncrasies and inconsistencies in Racket, so that those new to Racket will say ``ah, that makes sense'' rather than ``huh? what?'' @tt{#lang br} is not meant to hide the true nature of Racket, but rather defer certain parts of the learning curve.
To that end, this documentation not only explains the functions and forms in the Beautiful Racket library, but also how they depart from traditional or idiomatic Racket. (BTW ``Beautiful Racket'' is the name of the book, not an implication that the rest of Racket is less than beautiful. It is! But one thing at a time.)
@section{Conditionals}
@defmodule[br/conditional]
@defmodule[br/cond]
@defform[(while cond body ...)]
Loop over @racket[_body] expressions as long as @racket[_cond] is not @racket[#f]. If @racket[_cond] starts out @racket[#f], @racket[_body] expressions are not evaluated.
Loop over @racket[_body] as long as @racket[_cond] is not @racket[#f]. If @racket[_cond] starts out @racket[#f], @racket[_body] is never evaluated.
@examples[#:eval my-eval
(let ([x 42])
(while (positive? x)
(set! x (- x 1)))
x)
(let ([x 42])
(while (negative? x)
(unleash-zombie-army))
x)
]
@defform[(until cond body ...)]
Loop over @racket[_body] expressions until @racket[_cond] is not @racket[#f]. If @racket[_cond] starts out @racket[#f], @racket[_body] expressions are not evaluated.
@defform[(until cond body ...)]
Loop over @racket[_body] until @racket[_cond] is not @racket[#f]. If @racket[_cond] starts out not @racket[#f], @racket[_body] is never evaluated.
@examples[#:eval my-eval
(let ([x 42])
(until (zero? x)
(set! x (- x 1)))
x)
(let ([x 42])
(until (= 42 x)
(destroy-galaxy))
x)
]
@section{Datums}
@defmodule[br/datum]
A @defterm{datum} is a literal representation of Racket code that describes an S-expression. Unlike a string, a datum preserves the internal structure of the S-expression. Meaning, if the S-expression is a single value, or list-shaped, or tree-shaped, so is its corresponding datum.
Datums are made with @racket[quote] or its equivalent notation, the @litchar{'} prefix (see @secref["quote" #:doc '(lib "scribblings/guide/guide.scrbl")]).
When I use ``datum'' in its specific Racket sense, I use ``datums'' as its plural rather than ``data'' because that term has an existing, more generic meaning.
@defproc[
(format-datum
[datum-template symbol?]
[arg any/c?] ...)
[datum-form datum?]
[val any/c?] ...)
datum?]
tk
Similar to @racket[format], but the template @racket[_datum-form] is a datum, rather than a string, and the function returns a datum, rather than a string. Otherwise, the same formatting escapes can be used in the template (see @racket[fprintf]).
Two special cases. First, a string that describes a list of datums is parenthesized so the result is a single datum. Second, an empty string returns @racket[void] (not @racket[#f], because that's a legitimate datum).
@examples[#:eval my-eval
(format-datum '42)
(format-datum '~a "foo")
(format-datum '(~a ~a) "foo" 42)
(format-datum '~a "foo bar zam")
(void? (format-datum '~a ""))
(format-datum '~a #f)
]
@defproc[
(format-datums
[datum-form datum?]
[vals (listof any/c?)] ...)
(listof datum?)]
Like @racket[format-datum], but applies @racket[_datum-form] to the lists of @racket[_vals] in similar way to @racket[map], where values for the format string are taken from the lists of @racket[_vals] in parallel. This means that a) @racket[_datum-form] must accept as many arguments as there are lists of @racket[_vals], and b) the lists of @racket[_vals] must all have the same number of items.
Print the name and value of @racket[_expr] to @racket[current-error-port], but also return the evaluated result of @racket[_expr] as usual. This lets you see the value of an expression or variable at runtime without disrupting any of the surrounding code. Optionally, you can use @racket[_maybe-name] to change the name shown in @racket[current-error-port].
For instance, suppose you wanted to see how @racket[first-condition?] was being evaluted in this expression:
But be careful —in the example below, the result of the @racket[if] expression will be skipped in favor of the last expression, which will be the value of @racket[_x]:
A variant of @racket[report] for use with @secref["stx-obj" #:doc '(lib "scribblings/guide/guide.scrbl")]. Rather than print the whole object (as @racket[report] would), @racket[report-datum] prints only the datum inside the syntax object, but the return value is the whole syntax object.