The Kawa Scheme Language

The Kawa Scheme Language

Symbols and namespaces

An identifier is a name that appears in a program.

A symbol is an object representing a string that cannot be modified. This string is called the symbol's name. Unlike strings, two symbols whose names are spelled the same way are indistinguishable. A symbol is immutable (unmodifiable) and normally viewed as atomic. Symbols are useful for many applications; for instance, they may be used the way enumerated values are used in other languages.

In addition to the simple symbols or standard Scheme, Kawa also has compound (two-part) symbols.

Simple symbols

Simple symbols have no properties other than their name, an immutable string. They have the useful property that two simple symbols are identical (in the sense of eq?, eqv? and equal?) if and only if their names are spelled the same way. A symbol literal is formed using quote.

symbol? obj

Return #t if obj is a symbol, #f otherwise.

(symbol? 'foo)          ⇒ #t
(symbol? (car '(a b)))  ⇒ #t
(symbol? "bar")         ⇒ #f
(symbol? 'nil)          ⇒ #t
(symbol? '())           ⇒ #f
(symbol? #f)            ⇒ #f

symbol->string symbol

Return the name of symbol as an immutable string.

(symbol->string 'flying-fish)                   ⇒  "flying-fish"
(symbol->string 'Martin)                        ⇒  "Martin"
(symbol->string (string->symbol "Malvina"))     ⇒  "Malvina"

string->symbol string

Return the symbol whose name is string.

(eq? 'mISSISSIppi 'mississippi)
⇒ #f

(string->symbol "mISSISSIppi")
⇒ the symbol with name "mISSISSIppi"

(eq? 'bitBlt (string->symbol "bitBlt"))
⇒ #t

(eq? 'JollyWog (string->symbol (symbol->string 'JollyWog)))
⇒ #t

(string=? "K. Harper, M.D."
          (symbol->string (string->symbol "K. Harper, M.D.")))
⇒ #t

Namespaces and compound symbols

Different applications may want to use the same symbol to mean different things. To avoid such name clashes we can use compound symbols, which have two string parts: a local name and a namespace URI. The namespace-uri can be any string, but it is recommended that it have the form of an absolute URI. It would be too verbose to write the full URI all the time, so one usually uses a namespace prefix (namespace alias) as a short local alias to refer to a namespace URI.

Compound symbols are usually written using the infix colon operator:

prefix:local-name

where prefix is is namespace alias bound to some (lexically-known) namespace URI.

Compound symbols are used for namespace-aware XML processing.

Namespace objects

A namespace is a mapping from strings to symbols. The string is the local-name of resulting symbol. A namespace is similar to a Common Lisp package.

A namespace has a namespace-uri, which a string; it recommended that it have the form of an absolute URI. A namespace may optionally have a prefix, which is a string used when printing out symbols belonging to the namespace. (If you want for “equivalent symbols” (i.e. those that have the same local-name and same uri) to be the identical symbol object, then you should use namespaces whose prefix is the empty string.)

namespace name [prefix]

Return a namespace with the given name and prefix. If no such namespace exists, create it. The namespace-name is commonly a URI, especially when working with XML, in which case it is called a namespace-URI. However, any non-empty string is allowed. The prefix can be a string or a simple symbol. (If a symbol is used, then the symbol's local-name is used.) The default for prefix is the empty string. Multiple calls with the same arguments will yield the same namespace object.

The reader macro #,namespace is equivalent to the namespace function, but it is invoked at read-time:

#,(namespace "http://www.w3.org/1999/XSL/Transform" xsl)
(eq? #,(namespace "foo") (namespace "foo")) ⇒ #t

The form (,#namespace "" "") returns the default empty namespace, which is used for simple symbols.

namespace-uri namespace

Return the namespace-uri of the argument namespace, as a string.

namespace-prefix namespace

Return the namespace prefix of the argument namespace, as a string.

Compound symbols

A compound symbol is one that belongs to a namespace other than the default empty namespace, and (normally) has a non-empty namespace uri. (It is possible for a symbol to belong to a non-default namespace and have an empty namespace uri, but that is not recommended.)

symbol local-name namespace-spec

symbol local-name [uri [prefix]]

Construct a symbol with the given local-name and namespace. If namespace-spec is a namespace object, then find (or if needed construct) a symbol with the given local-name belonging to the namespace. Multiple calls to symbol with the same namespace and local-name will yield the same symbol object.

If uri is a string (optionally followed by a prefix), then:

(symbol lname uri [prefix])

is equivalent to:

(symbol lname (namespace uri [prefix]))

Using #t for the namespace-spec is equivalent to using the empty namespace #,(namespace "").

Using #!null or #f for the namespace-spec creates an uninterned symbol, which does not belong to any namespace.

symbol-local-name symbol

Return the local name of the argument symbol, as an immutable string. (The string is interned, except in the case of an uninterned symbol.)

symbol-prefix symbol

Return the prefix of the argument symbol, as an immutable (and interned) string.

symbol-namespace-uri symbol

Return the namespace uri of the argument symbol, as an immutable (and interned) string.

symbol-namespace symbol

Return the namespace object (if any) of the argument symbol. Returns #!null if the symbol is uninterned.

symbol=? symbol_1 symbol_2 symbol_3

Return #t if the symbols are equivalent as symbols, i.e., if their local-names and namespace-uris are the same. They may have different values of symbol-prefix and symbol-namespace. If a symbol is uninterned (or is #!null) then symbol=? returns the same result as eq?.

Two symbols are equal? or eqv? if they're symbol=?.

Namespace aliases

A namespace is usually referenced using a shorter namespace alias, which is is a lexical definition that binds a namespace prefix to a namespace object (and thus a namespace uri). This allows using compound symbols as identifiers in Scheme programs.

define-namespace name namespace-name

Defines name as a namespace prefix - a lexically scoped "nickname" for the namespace whose full name is namespace-name, which should be a non-empty string literal. It is customary for the string have syntactic form of an absolute URI, but any non-empty string is acceptable and is used without further interpretation.

Any symbols in the scope of this definitions that contain a colon, and where the part before the colon matches the name will be treated as being in the package/namespace whose global unique name is the namespace-name.

Has mostly the same effect as:

(define-constant name #,(namespace namespace-name)

However, using define-namespace (rather than define-constant) is recommended if you want to use compound symbols as names of variables, especially local variables, or if you want to quote compound symbols.

Note that the prefix is only visible lexically: it is not part of the namespace, or thus indirectly the symbols, and so is not available when printing the symbol. You might consider using define-xml-namespace as an alternative.

A namespace is similar to a Common Lisp package, and the namespace-name is like the name of the package. However, a namespace alias belongs to the lexical scope, while a Common Lisp package nickname is global and belongs to the package itself.

If the namespace-name starts with the string "class:", then the name can be used for invoking Java methods (see the section called “Calling Java methods from Scheme”) and accessing fields (see the section called “Accessing object fields”).

You can use a namespace as an abbreviation or renaming of a class name, but as a matter of style define-alias is preferred.

define-private-namespace name namespace-name

Same as define-namespace, but the prefix name is local to the current module.

For example you might have a set of a geometry definitions defined under the namespace-uri "http://foo.org/lib/geometry":

(define-namespace geom "http://foo.org/lib/geometry")
(define (geom:translate x y)
  (java.awt.geom.AffineTransform:getTranslateInstance x y))
(define geom:zero (geom:translate 0 0))
geom:zero
  ⇒ AffineTransform[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]

You could have some other definitions for complex math:

(define-namespace complex "http://foo.org/lib/math/complex")
(define complex:zero +0+0i)

You can use a namespace-value directly in a compound name:

(namespace "http://foo.org/lib/geometry"):zero
  ⇒ AffineTransform[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]

The variation define-xml-namespace is used for the section called “Creating XML nodes”.

define-xml-namespace prefix "namespace-uri"

Defines a namespace with prefix prefix and URI namespace-uri. This is similar to define-namespace but with two important differences:

  • Every symbol in the namespace automatically maps to an element-constructor-type, as with the html namespace.

  • The prefix is a component of the namespace object, and hence indirectly of any symbols belongining to the namespace.

Thus the definition is roughly equivalent to:

(define-constant name #,(namespace namespace-name name)

along with an infinite set of definitions, for every possible tag:

(define (name:tag . rest) (apply make-element 'name:tag rest))
$ kawa --output-format xml
#|kawa:1|# (define-xml-namespace na "Namespace1")
#|kawa:2|# (define-xml-namespace nb "Namespace1")
#|kawa:3|# (define xa (na:em "Info"))
#|kawa:4|# xa
<na:em xmlns:na="Namespace1">Info</na:em>
#|kawa:5|# (define xb (nb:em "Info"))
#|kawa:6|# xa
<nb:em xmlns:nb="Namespace1">Info</nb:em>

Note that the prefix is part of the qualified name (it is actually part of the namespace object), and it is used when printing the tag. Two qualified names (symbols) that have the same local-name and the same namespace-name are considered equal, even if they have different prefix. You can think of the prefix as annotation used when printing, but not otherwise part of the “meaning” of a compound symbol. They are the same object if they also have the same prefix. This is an important different from traditional Lisp/Scheme symbols, but it is how XML QNames work.

#|kawa:7|# (instance? xb na:em)
true
#|kawa:8|# (eq? 'na:em 'nb:em)
false
#|kawa:9|# (equal? 'na:em 'nb:em)
true
#|kawa:10|# (eqv? 'na:em 'nb:em)
true

(Note that #t is printed as true when using XML formatting.)

The predefined html prefix could be defined thus:

(define-xml-namespace html "http://www.w3.org/1999/xhtml")

Keywords

Keywords are similar to symbols. They are used mainly for specifying keyword arguments.

Historically keywords have been self-evaluating (you did not need to quote them). This is changing: you should quote a keyword if you want a literal keyword value, and not quote it if it is used with a keyword argument. (This change is a work-in-progress.)

keyword ::= identifier:

A keyword is a single token; therefore no whitespace is allowed between the identifier and the colon (which is not considered part of the name of the keyword).

keyword? obj

Return #t if obj is a keyword, and otherwise returns #f.

keyword->string keyword

Returns the name of keyword as a string. The name does not include the final #\:.

string->keyword string

Returns the keyword whose name is string. (The string does not include a final #\:.)

Special named constants

#!optional

Special self-evaluating literal used in lambda parameter lists before optional parameters.

#!rest

Special self-evaluating literal used in lambda parameter lists before the rest parameter.

#!key

Special self-evaluating literal used in lambda parameter lists before keyword parameters.

#!eof

The end-of-file object.

Note that if the Scheme reader sees this literal at top-level, it is returned literally. This is indistinguishable from coming to the end of the input file. If you do not want to end reading, but want the actual value of #!eof, you should quote it.

#!void

The void value. Same as (values). If this is the value of an expression in a read-eval-print loop, nothing is printed.

#!null

The Java null value. This is not really a Scheme value, but is useful when interfacing to low-level Java code.