For Gauche 0.9.9


Next: , Previous: , Up: Core library   [Contents][Index]

6.8 Keywords

Builtin Class: <keyword>

Keywords are a subtype of symbols that are automatically bound to itself. It is extensively used in named arguments (keyword arguments), and keyword-value list.

See Making procedures for how Gauche supports keyword arguments, and let-keywords macro (Optional argument parsing) for parsing keyword-value list manually.

Keywords used to be a disjoint type from symbols. Since it isn’t conformant to R7RS, in which symbols can begin with :, we’ve introduced two modes since 0.9.5; keywords can be a disjoint type of its own, or it can be a subtype of symbols.

The behavior can be switched by environment variables. If the environment variable GAUCHE_KEYWORD_DISJOINT is defined when gosh starts up, keywords and symbols are disjoint. Otherwise, if the environment variable GAUCHE_KEYWORD_IS_SYMBOL is defined, keywords are a subtype of symbols.

The default behavior when neither environment variables are defined has been switched since 0.9.8. GAUCHE_KEYWORD_DISJOINT was assumed in 0.9.7 and before, while GAUCHE_KEYWORD_IS_SYMBOL is assumed in 0.9.8 and after.

Most typical code run in either mode, but there can be some code that behaves differently. See Keyword and symbol integration, for effect of the change.

In future we’ll stop supporting GAUCHE_KEYWORD_DISJOINT, so we recommend you to ensure applications to run on the current default mode.

Reader Syntax: :name

Read to a keyword whose name is :name.

Function: keyword? obj

Returns #t if obj is a keyword.

Function: make-keyword name

Returns a keyword whose name is name prepended by :. The name argument can be a string or a symbol.

(make-keyword "foo")  ⇒ :foo

(make-keyword 'foo)   ⇒ :foo
Function: keyword->string keyword

Returns the name (without the initial :) of the keyword keyword, in a string.

(keyword->string :foo) ⇒ "foo"
Function: get-keyword key kv-list :optional fallback

A useful procedure to extract a value from key-value list. A key-value list kv-list must contains even number of elements; the first, third, fifth … elements are regarded as keys, and the second, fourth, sixth … elements are the values of the preceding keys.

This procedure looks for key from the keys, and if it finds one, it returns the corresponding value. If there are more than one matching keys, the leftmost one is taken. If there is no matching key, it returns fallback if provided, or signals an error otherwise.

It is an error if kv-list is not a proper, even-number element list.

Actually, ‘keywords’ in the keyword-value list and the key argument need not be a keyword—it can be any Scheme object. Key comparison is done by eq?.

This procedure is taken from STk.

(get-keyword :y '(:x 1 :y 2 :z 3))
  ⇒ 2
(get-keyword 'z '(x 1 y 2 z 3))
  ⇒ 3

(get-keyword :t '(:x 1 :y 2 :z 3))
  ⇒ #<error>
(get-keyword :t '(:x 1 :y 2 :z 3) #f)
  ⇒ #f
Macro: get-keyword* key kv-list :optional fallback

Like get-keyword, but fallback is evaluated only if kv-list does not have key.

Function: delete-keyword key kv-list
Function: delete-keyword! key kv-list

Removes all the keys and values from kv-list for keys that are eq? to key.

delete-keyword doesn’t change kv-list, but the returned list may share the common tail of it.

delete-keyword! doesn’t allocate, and may destructively changes kv-list. You still have to use the returned value, for the original list may not be changed if its first key matches key.

If there’s no key that matches key, kv-list is returned.

(delete-keyword :y '(:x 1 :y 2 :z 3 :y 4))
 ⇒ (:x 1 :z 3)
Function: delete-keywords keys kv-list
Function: delete-keywords! keys kv-list

Similar to delete-keyword and delete-keyword!, but you can specify a list of objects in keys; when a key in kv-list matches any of keys, the key and the following value is removed from kv-list.

(delete-keywords '(:x :y) '(:x 1 :y 2 :z 3 :y 4))
 ⇒ (:z 3)

Previous: , Up: Keywords   [Contents][Index]

6.8.1 Keyword and symbol integration

In older versions of Gauche, keywords are of disjoint type from symbols, and they are self-evaluating objects. To maintain the compatibility, the current Gauche makes symbols that begins with : automatically bound to itself.

On the surface it won’t make much difference; you can write a keyword :key, which evaluates to itself; so you can pass and receive keyword arguments just as they used to be. If you use :key as variables, however, e.g. (define :key 3), the value of :key in your module changes (it won’t affect other modules, which refer to the binding of :key in gauche.keyword module).

However, there are several subtle points that do make difference, that breaks compatibility of legacy code. We explain here how to change the code that works in both ways.

If you find a problem in new mode and want to get the old behavior until you change the code, you can set the environment variable GAUCHE_KEYWORD_DISJOINT.

(symbol? :key) used to return #f, now returns #t

keyword? always returns #t on keywords, but if you need to switch behavior depending whether an object is a symbol or a keyword, you should test keyword-ness first.

;; behaved differently in 0.9.7 and before
(cond
  [(symbol? x) (x-is-symbol)]
  [(keyword? x) (x-is-keyword)])

;; works on all versions
(cond
  [(keyword? x) (x-is-keyword)]
  [(symbol? x) (x-is-symbol)])

Literal keywords in pattern matching

In the old versions, when keywords appear in a pattern of util.match or syntax-rules, they only matched to themselves. In the current version, such keywords in a pattern are treated as pattern variables, since they are symbols.

;; In the old versions
(match '(a b) [(:key z) (list :key z)] [_ "nope"])
   ⇒ "nope"

;; In the current version
;; :key is treated just as a pattern variable
(match '(a b) [(:key z) (list :key z)] [_ "nope"])
   ⇒ (a b)

The same thing happens to the patterns in syntax-rules.

To make the code work in both versions, explicitly mark the keywords as literals.

As of Gauche 0.9.5, match warns if you have unquoted keywords in match patterns.

Displaying keywords

(display :key) used to print key (no colon), while it now prints :key.

You can use (display (keyword->string :key)) which prints key in both versions.

For R7RS code, quote them or import Gauche modules

Keywords (symbols beginning with :) are automatically bound to itself in the gauche.keyword module.

Gauche code inherits the gauche module by default, which inherits keyword, so you can see the binding of the keyword by default.

In R7RS code, however, you don’t inherit gauche, so symbols beginning with : are just ordinary symbols by default. Usually you do (import (gauche base)) to use Gauche built-ins, and that makes binding of gauche.keyword available in your code, too (since gauche.base inherits gauche.keyword). But keep this in mind just in case you want to handle keywords in your R7RS code separate from Gauche procedures—you have to either say (import (gauche keyword)) to get just the self-bound keywords, or quote them.

(import (scheme base))

:foo ⇒ ERROR: unbound variable: :foo

(import (gauche base))

:foo ⇒ :foo

In the following example, the R7RS library foo imports only copy-port from (gauche base); in that case, you have to import (gauche keyword) separately in order to use :size keyword without quoting. (Or add :size explicitly in the imported symbol list of (gauche base).)

(define-library (foo)
  (import (scheme base)
          (only (gauche base) copy-port)
          (gauche keyword))
  (export cat)        

  (begin
    (define (cat)
      (copy-port (current-input-port)
                 (current-output-port)
                 :size 4096))))

Previous: , Up: Keywords   [Contents][Index]