Racket’s stringlike types include strings, symbols, identifiers, keywords, and path strings. They are “stringlike” in the sense that they all consist of a sequence of Unicode characters, and can easily be converted among one another.
A standard string is enclosed in "double quotes". A literal double-quote character can be escaped as \".
1 2 | "one string" "two \"strings\"" |
By default, strings will print as literal expressions (meaning, their printed form can be reused as input). To print strings in the usual friendly way, use display or displayln. To print strings in the raw style used on the REPL, use print or println:
1 2 3 4 5 | "one literal string" "two literal \"strings\"" one displayed string two displayed "strings" "one printed string\n""two printed \"strings\"" |
Strings can also include the usual escape characters to represent ASCII whitespace, like \t for tab and \n for linefeed, as well as special classes of escape characters like \x for hex numbers and \u for Unicode characters. (See the Racket docs for the full list.)
Racket also has the usual string-manipulation functions—string-split, string-join, string-append, format, etc.—that do what you’d expect.
To make multiline strings inside a program, two options.
You can use a here string, which is introduced by #<< and a delimiter name, followed by the string starting on the next line, ending with the delimiter on its own line:
1 2 3 4 5 | A wonderful multiline string that goes on seemingly forever. |
You can also use an @-expression, which is a special textual kind of S-expression, by adding the at-exp metalanguage to the #lang line:
1 2 3 4 5 6 7 8 9 10 | #lang at-exp br ; note `at-exp` here
(define str @string-append{
A wonderful
multiline string
that goes on
seemingly
forever.})
(display str) ; same result as above
|
A nice advantage of @-expressions over here strings is that they can include normally evaluated subexpressions, the results of which are spliced into the string. These subexpressions are prefixed with another @:
1 2 3 4 5 6 7 8 9 10 11 12 | #lang at-exp br (define base 2) (define pow 8) (define str @string-append{ A wonderful multiline string that goes on @(number->string (expt base pow)) years.}) (display str) |
1 2 3 4 | A wonderful multiline string that goes on 256 years. |
@-expression syntax in the Scribble docs
A symbol is like a string, but written with a single ' prefix rather than surrounding double quotes. A symbol cannot contain spaces unless the whole symbol is surrounded with | vertical bars |:
1 2 3 4 | "string" 'symbol "two-word string" '|two-word symbol| |
Symbols have one special property that strings do not: they are interned, meaning Racket guarantees that all instances of a particular symbol refer to only one object in memory. Therefore, it’s a good habit to use symbols when you need high-speed equality checking, because symbols can be compared with eq?, which is much faster than the equal? required by strings:
string->symbol and symbol->string are available for explicit conversions.
An identifier is a name that appears in a program. For its behavior, see identifiers. Within a datum, an identifier is represented with a symbol:
1 2 3 4 5 | (define foo "see") (define bar "saw") (string-append foo bar) ; "seesaw" '(string-append foo bar) ; '(string-append foo bar) (andmap symbol? '(string-append foo bar)) ; #t |
Here, (string-append foo bar) is an S-expression consisting of a list containing three identifiers. When evaluated normally, it becomes "seesaw". When converted to a datum, it becomes a list of three symbols (= 'string-append, 'foo, 'bar).
Conversely, when a datum is evaluated, symbols inside are treated as identifiers. For instance, when the three symbols 'cons, 'foo, and 'bar are grouped into a list and evaluated, they are treated as identifiers:
In these situations, if you really want a symbol in the result, then put two ' prefixes on the original item:
Most strings can be converted into identifiers, though there are some reserved characters and special conventions. For instance, strings representing numbers cannot be used as identifiers.
Identifiers in the Racket Guide
A keyword is used to introduce a keyword argument either in a function definition or a call to that function. Below, #:base and #:pow are keywords:
It’s usually only necessary to think about keywords as data if you’re writing macros or other special operations that programmatically manipulate keyword arguments, in which case you can use string->keyword and keyword->string to convert.
1 2 3 4 5 6 7 | (define (f #:base x #:pow y) (expt x y)) (f #:base 2 #:pow 8) ; 256 (keyword-apply f '(#:base #:pow) '(2 8) empty) ; 256 (keyword-apply f (list (string->keyword "base") (string->keyword "pow")) '(2 8) empty) ; 256 |
For more about the use of keyword arguments, see functions.
A line comment begins with ;. A multiline comment is delimited with #| and |#. A single S-expression can be commented with #;.
1 2 | "not a comment" '(1 2 3 4) |
A path string is not a distinct type, but rather the subset of strings that can be converted into a valid path. Many Racket functions that manipulate paths will accept either a path or a path string, so it’s often not necessary to manually convert the input argument with string->path:
1 2 | (file-exists? (string->path "/usr/bin/racket")) ; #t (file-exists? "/usr/bin/racket") ; #t |
A path represents a file location. Paths are similar to strings. But it’s slightly misleading to categorize them as “stringlike”, because they’re made of a sequence of bytes rather than Unicode characters. In Racket, this is called a byte string. It’s a distinct data type from an ordinary Unicode string.
In practice, many paths can be converted to an ordinary string and back to a path. So as a convenience, Racket offers path->string and string->path:
1 2 3 | "/usr/bin/racket" (string->path "/usr/bin/racket") (path->string (string->path "/usr/bin/racket")) |
1 2 3 | "/usr/bin/racket" #<path:/usr/bin/racket> "/usr/bin/racket" |
But some paths can’t be converted to a string without losing data. In general, path->string is intended for making user-readable versions of paths. It’s unwise to manipulate paths by converting them to strings and back again. Better to use Racket’s dedicated path-manipulation functions.
Paths in the Racket Reference