5.5 Guile
Guile is an acronym for GNU’s Ubiquitous Intelligent Language for Extensions. It provides a Scheme interpreter conforming to the R5RS language specification and a number of convenience functions. For information about the language, refer to Revised(5) Report on the Algorithmic Language Scheme. For a detailed description of Guile and its features, see Overview in The Guile Reference Manual.
The guile module provides an interface to Guile that
allows for writing GNU Dico modules in Scheme. The module is loaded
using the following configuration file statement:
load-module mod-name {
command "guile [options]"
" init-script=script"
" init-args=args"
" init-fun=function";
}
The init-script parameter specifies the name of a Scheme
source file to be loaded in order to initialize the module.
The init-args parameter supplies additional arguments to the
module. They will be accessible to the script via
command-line function. This parameter is optional.
The init-fun parameter specifies the name of a function that
will be invoked to perform initialization of the module and of
particular databases. See Guile Initialization, for a description
of initialization sequence. Optional arguments, options, are:
debugEnable Guile debugging and stack traces.
nodebugDisable Guile debugging and stack traces (default).
load-path=pathAppend directories from path to the list of directories which should be searched for Scheme modules and libraries. The path must be a list of directory names, separated by colons.
This option modifies the value of Guile’s
%load-pathvariable. See the section Configuration and Installation in the Guile Reference Manual.
Guile databases are declared using the following syntax:
database {
name "dbname";
handler "mod-name [options] cmdline";
}
where:
- dbname
gives the name for this database,
- mod-name
the name given to Guile module in
load-modulestatement (see above),- options
-
options that override global settings given in the
load-modulestatement. The following options are understood:init-script,init-args, andinit-fun. Their meaning is the same as forload-modulestatement (see above), except that they affect only this particular database. - cmdline
the command line that will be passed to the Guile
open-dbcallback function (see open-db).
5.5.1 Virtual Functions
A database handled by the guile module is assigned a
virtual function table. This table is an association list which
keeps Scheme call-back functions implemented to perform
particular tasks on that database. In this list, the car of
each element contains the name of a function, and its cdr gives
the corresponding function. The defined function names and their
semantics are:
- open
Open the database.
- close
Close the database.
- descr
Return a short description of the database.
- info
Return a full information about the database.
- define
Define a word.
- match
Look up a word in the database.
- output
Output a search result.
- result-count
Return number of entries in the result.
For example, the following is a valid virtual function table:
(list (cons "open" open-module)
(cons "close" close-module)
(cons "descr" descr)
(cons "info" info)
(cons "define" define-word)
(cons "match" match-word)
(cons "output" output)
(cons "result-count" result-count))
Apart from a per-database virtual table, there is also a global virtual function table, which supplies entries missing in the former. Both tables are created during the module initialization, as described in the next subsection.
The purposes of particular virtuals functions are described in Guile API.
5.5.2 Guile Initialization
The following configuration statement causes loading and
initialization of the guile module:
load-module mod-name {
command "guile init-script=script"
" init-fun=function";
}
Upon module initialization stage, the module attempts to load the
file named script. The file is loaded using
primitive-load call (see Loading in The Guile Reference Manual), i.e. the load paths are not
searched, so script must be an absolute path name. The
init-fun parameter supplies the name of the initialization
function. This Scheme function constructs virtual
function tables for the module itself and for each database that uses
this module. It must be declared as follows:
(define (function arg) ...)
This function is called several times. First of all, it is called after
the script is loaded. This time it is given #f as its
argument, and its return value is saved as a global function table.
Then, it is called for each database statement that has
mod-name (used in load-module above) in its
handler keyword, e.g.:
database {
name db-name;
handler "mod-name …";
}
This time, it is given db-name as its argument and the value it returns is stored as the virtual function table for this particular database.
The following example function returns a complete virtual function table:
(define-public (my-dico-init arg)
(list (cons "open" open-module)
(cons "close" close-module)
(cons "descr" descr)
(cons "info" info)
(cons "lang" lang)
(cons "define" define-word)
(cons "match" match-word)
(cons "output" output)
(cons "result-count" result-count)))
5.5.3 Guile API
This subsection describes callback functions that a Guile database module must provide. Each description begins with the function prototype and its entry in the virtual function table.
Callback functions can be subdivided into two groups: database functions and search functions.
Database callback functions are responsible for opening and closing databases and for returning information about them.
- Guile Callback: open-db name . args
Virtual table:
(cons "open" open-db)
Open the database. The argument name contains database name as given in the
namestatement of the correspondingdatabaseblock (see Databases). Optional argument args is a list of command line parameters obtained from cmdline inhandlerstatement (see guile-cmdline). For example, if the configuration file contained:database { name "foo"; handler "guile db=file 1 no"; }then the
open-dbcallback will be called as:(open-db "foo" '("db=file" "1" "no"))The
open-dbcallback returns a database handle, i.e. an opaque object that will subsequently be used to identify this database. This value, hereinafter named dbh, will be passed to another callback functions that need to access the database.The return value
#for'()indicates an error.
- Guile Callback: close-db dbh
Virtual Table:
(cons "close" close-db)
Close the database. This function is called during the cleanup procedure, before termination of
dicod. The argumentdbhis a database handle returned byopen-db.The return value from
close-dbis ignored. To communicate errors to the daemon, throw an exception.
- Guile Callback: descr dbh
Virtual Table:
(cons "descr" descr)
Return a short textual description of the database, for use in
SHOW DBoutput. If there is no description, returns#for'().The argument dbh is a database handle returned by
open-db.This callback is optional. If it is not defined, or if it returns
#f('()), the text fromdescriptionstatement is used (see description). Otherwise, if nodescriptionstatement is present, an empty string will be returned.
- Guile Callback: info dbh
Virtual Table:
(cons "info" info)
Return a verbose, eventually multi-line, textual description of the database, for use in
SHOW INFOoutput. If there is no description, returns#for'().The argument dbh is a database handle returned by
open-db.This callback is optional. If it is not defined, or if it returns
#f('()), the text frominfostatement is used (see info). If there is noinfostatement, the string ‘No information available’ is used.
- Guile Callback: lang dbh
Virtual Table:
(cons "lang" lang)
Return a
consof languages supported by this database: Itscaris a list of source languages, and itscdris a list of destination languages. For example, the following return value indicates that the database contains translations from English to French and Spanish:(cons (list "en") (list "fr" "es"))
A database is searched in a two-phase process. First, an appropriate
callback is called to do the search: define-word is called for
DEFINE searches and match-word is called for matches.
This callback returns an opaque entity, called result handle,
which is then passed to the output callback, which is responsible
for outputting it.
- Guile Callback: define-word dbh word
Virtual Table:
(cons "define" define-word)
Find definitions of word word in the database dbh. Return a result handle. If nothing is found, return
#for'().The argument dbh is the database handle returned by
open-db.
- Guile Callback: match-word dbh strat key
Virtual Table:
(cons "match" match-word)
Find in the database dbh all headwords that match key, using strategy strat. Return a result handle. If nothing is found, return
#for'().The key is a Dico Key object, which contains information about the word being looked for. To obtain the actual word, use the
dico-key->wordfunction (see dico-key->word).The argument dbh is a database handle returned by
open-db. The matching strategy strat is a special Scheme object that can be accessed using a set of functions described below (see Dico Scheme Primitives).
- Guile Callback: result-count resh
Virtual Table:
(cons "result-count" result-count)
Return the number of elements in the result set resh.
- Guile Callback: output resh n
Virtual Table:
(cons "output" output)
Output nth result from the result set resh. The argument resh is a result handle returned by
define-wordormatch-wordcallback.The data must be output to the current output port, e.g. using
displayorformatprimitives. If resh represents a match result, the output must not be quoted or terminated by newlines.It is guaranteed that the
outputcallback will be called as many times as there are elements in resh (as determined by theresult-countcallback) and that for each subsequent call the value of n equals its value from the previous call incremented by one.At the first call n equals 0.
5.5.4 Dico Scheme Primitives
GNU Dico provides the following Scheme primitives for accessing various
fields of the strat and key arguments to match callback:
- Function: dico-key? obj
Return ‘#t’ if obj is a Dico key object.
- Function: dico-key->word key
Extract the lookup word from the key object key.
- Function: dico-make-key strat word
Create new key object from strategy strat and word word.
- Function: dico-strat-selector? strat
Return true if strat has a selector (see Selector).
- Function: dico-strat-select? strat word key
Return true if key matches word as per strategy selector strat. The key is a ‘Dico Key’ object.
- Function: dico-strat-name strat
Return the name of strategy strat.
- Function: dico-strat-description strat
Return a textual description of the strategy strat.
- Function: dico-strat-default? strat
Return
trueif strat is a default strategy. See default strategy.
- Function: dico-register-strat strat descr [fun]
Register a new strategy. If fun is given it will be used as a callback for that strategy. Notice, that you can use strategies implemented in Guile in your C code as well (see strategy).
The selector function must be declared as follows:
(define (fun key word) ...)
It must return
#tif key matches word, and#fotherwise.
5.5.5 Example Module
In this subsection we will show how to build a simple dicod module
written in Scheme. The source code of this module, called
listdict.scm and a short database for it, numerals-pl.db, are
shipped with the distribution in the directory examples.
The database is stored in a disk file in form of a list. The first
two elements of this list contain database description and full
information strings. Rest of elements are conses, whose car
contains the headword, and cdr contains the corresponding
dictionary article. Following is an example of such a database:
("Short English-Norwegian numerals dictionary"
"Short English-Norwegian dictionary of numerals (1 - 7)"
("one" . "en")
("two" . "to")
("three" . "tre")
("four" . "fire")
("five" . "fem")
("six" . "seks")
("seven" . "sju"))
We wish to declare such databases in dicod.conf the following way:
database {
name "numerals";
handler "guile example.db";
}
Thus, the rest argument to ‘open-db’ callback will be
‘("guile" "example.db")’ (see open-db). Given this, we may
write the callback as follows:
(define (open-db name . rest)
(let ((db (with-input-from-file
(cadr rest)
(lambda () (read)))))
(cond
((list? db) (cons name db))
(else
(format (current-error-port) "open-module: ~A: invalid format\n"
(car args))
#f))))
The list returned by this callback will then be passed as a database handle to another callback functions. To facilitate access to particular elements of this list, it is convenient to define the following syntax:
(define-syntax db:get
(syntax-rules (info descr name corpus)
((db:get dbh name) ;; Return the name of the database.
(list-ref dbh 0))
((db:get dbh descr) ;; Return the desctiption.
(list-ref dbh 1))
((db:get dbh info) ;; Return the info string.
(list-ref dbh 2))
((db:get dbh corpus) ;; Return the word list.
(list-tail dbh 3))))
Now, we can write ‘descr’ and ‘info’ callbacks:
(define (descr dbh) (db:get dbh descr)) (define (info dbh) (db:get dbh info))
The two callbacks ‘define-word’ and ‘match-word’ provide
the core module functionality. Their results will be passed to
‘output’ and ‘result-count’ callbacks as a “result handler”
argument. In the spirit of Scheme, we make the result a list. Its
car is a boolean value: #t, if the result
comes from ‘define-word’ callback, and #f if it comes from
‘match-word’. The cdr of this list contains a list of
matches. For ‘define-word’, it is a list of conses copied from
the database word list, whereas for ‘match-word’, it is a list of
headwords.
The ‘define-word’ callback returns all list entries whose
cars contain the look up word. It uses mapcan
function, which is supposed to be defined elsewhere:
(define (define-word dbh word)
(let ((res (mapcan (lambda (elt)
(and (string-ci=? word (car elt))
elt))
(db:get dbh corpus))))
(and res (cons #t res))))
The ‘match-word’ callback (see match-word) takes three arguments: a database handler dbh, a strategy descriptor strat, and a word word to look for. The result handle it returns contains a list of headwords from the database that match word in the sense of strat. Thus, the behavior of ‘match-word’ depends on the strat. To implement this, let’s define a list of directly supported strategies (see below for definitions of particular ‘match-’ functions):
(define strategy-list
(list (cons "exact" match-exact)
(cons "prefix" match-prefix)
(cons "suffix" match-suffix)))
The ‘match-word’ callback will then select an entry from
that list and call its cdr, e.g.:
(define (match-word dbh strat key)
(let ((sp (assoc (dico-strat-name strat) strategy-list)))
(let ((res (cond
(sp
((cdr sp) dbh strat (dico-key->word key)))
If the requested strategy is not in that list, the function will use the selector function if it is available, and the default matching function otherwise:
((dico-strat-selector? strat)
(match-selector dbh strat key))
(else
(match-default dbh strat (dico-key->word key))))))
Notice the use of dico-key->word function to extract the actual
lookup word from the key object.
To summarize, the ‘match-word’ callback is:
(define (match-word dbh strat key)
(let ((sp (assoc (dico-strat-name strat) strategy-list)))
(let ((res (cond
(sp
((cdr sp) dbh strat (dico-key->word key)))
((dico-strat-selector? strat)
(match-selector dbh strat key))
(else
(match-default dbh strat (dico-key->word key))))))
(if res
(cons #f res)
#f))))
Now, let’s create the ‘match-’ functions it uses. The ‘exact’ strategy is easy to implement:
(define (match-exact dbh strat word)
(mapcan (lambda (elt)
(and (string-ci=? word (car elt))
(car elt)))
(db:get dbh corpus)))
The ‘prefix’ and ‘suffix’ strategies are implemented using
SRFI-13 (see SRFI-13 in The Guile Reference Manual)
functions string-prefix-ci? and string-suffix-ci?, e.g.:
(define (match-prefix dbh strat word)
(mapcan (lambda (elt)
(and (string-prefix-ci? word (car elt))
(car elt)))
(db:get dbh corpus)))
Notice that whereas the ‘prefix’ strategy is defined by the server itself, the ‘suffix’ strategy is an extension, and should therefore be registered:
(dico-register-strat "suffix" "Match word suffixes")
The match-selector function is pretty similar to its
siblings, except that it uses dico-strat-select?
(see dico-strat-select?) to select the
matching elements. This also leads to this function expecting
a key as its third argument, in contrast to the previous
matchers, which expect the actual lookup word there:
(define (match-selector dbh strat key)
(mapcan (lambda (elt)
(and (dico-strat-select? strat (car elt) key)
(car elt)))
(db:get dbh corpus)))
Finally, the match-default is a variable that refers to
the default matching strategy for this module, e.g.:
(define match-default match-prefix)
The two callbacks left to define are ‘result-count’ and
‘output’. The first of them simply returns the number of
elements in cdr of the result:
(define (result-count rh) (length (cdr rh)))
The behavior of ‘output’ depends on whether the result is produced by ‘define-word’ or by ‘match-word’.
(define (output rh n)
(if (car rh)
;; Result comes from DEFINE command.
(let ((res (list-ref (cdr rh) n)))
(display (car res))
(newline)
(display (cdr res)))
;; Result comes from MATCH command.
(display (list-ref (cdr rh) n))))
Finally, at the end of the module the callbacks are made known to
dicod by the module initialization function:
(define-public (example-init arg)
(list (cons "open" open-module)
(cons "descr" descr)
(cons "info" info)
(cons "define" define-word)
(cons "match" match-word)
(cons "output" output)
(cons "result-count" result-count)))
Notice, that in this implementation ‘close-db’ callback was not needed.






