For Gauche 0.9.7

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

6.8 Keywords

Builtin Class: <keyword>

A keyword is a sort of a special symbol that is automatically quoted. It is extensively used in pass-by-name 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.

Unlike Common Lisp, keywords and symbols have been distinct types in Gauche. Since it isn’t conformant to R7RS, in which symbols can begin with :, we’re moving on to integrate keywords and symbols— that is, a keyword will be evaluated as an identifier, just like symbols, but just happens to have itself as a value.

The integration may break the backward compatibility, we haven’t turned it on by default. When you set the environment variable GAUCHE_KEYWORD_IS_SYMBOL, keywords become a subtype of symbols;

Our plan is to make keywords as a subtype of symbols by default in near future. So we urge developers to test their libraries and applications with GAUCHE_KEYWORD_IS_SYMBOL to make sure the change won’t break them. See Keyword and symbol integration, for the hints to keep the compatibility.

Reader Syntax: :name

Read to a keyword whose name is name. (Note that the preceding ’:’ is not a part of the keyword’s name.)

Function: keyword? obj

Returns #t if obj is a keyword.

Function: make-keyword name

Returns a keyword whose name is name, which can be can be a string or a symbol.

(make-keyword "foo")  ⇒ :foo

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

Returns the name 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 future versions of Gauche, keywords will become symbols, automatically bound to itself by default. 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 like as they are now. You will be able to use :key as variables, e.g. (define :key 3), which changes the value of :key in your module, but that isn’t allowed in the current version of Gauche and it will be upper-compatible change. (We assume you know what you’re doing if you redefine keywords; still the effect stays local in your module and other module that import yours.)

However, there are several subtle points that do make difference, that would break backward compatibility unless you code carefully. We explain here how to write code that works in the current Gauche and will keep working after we make the change.

You can test if your library/application works after the change, by setting the environment variable GAUCHE_KEYWORD_IS_SYMBOL.

(symbol? :key) that returns #f now, will return #t

You will still be able to distinguish keywords by keyword?; but if you need to switch behavior depending whether an object is a symbol or a keyword, you have to test keyword-ness first.

;; will break
  [(symbol? x) (x-is-symbol)]
  [(keyword? x) (x-is-keyword)])

;; will work on both versions
  [(keyword? x) (x-is-keyword)]
  [(symbol? x) (x-is-symbol)])

Literal keywords in pattern matching

In the current version, when keywords appear in a pattern of util.match or syntax-rules, they only match to themselves. After we make keywords as a subtype of symbols, such keywords in a pattern are treated as pattern variables, just like symbols.

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

;; After keyword symbol integration;
;; :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

Now (display :key) prints key (no colon), while it will print :key in future.

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

For R7RS code, quote them or import Gauche modules

After integration, keywords (i.e. symbols that begins 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 (gacueh 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)        

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

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