diff options
author | Neil Jerram <neil@ossau.uklinux.net> | 2001-08-24 09:40:29 +0000 |
---|---|---|
committer | Neil Jerram <neil@ossau.uklinux.net> | 2001-08-24 09:40:29 +0000 |
commit | a0e07ba4ec86e4df014fee0666f18ece5a4d2471 (patch) | |
tree | ebe6546fc93fdcb3e2e1fdfbe55d809914b94ad8 /doc/tutorial/guile-tut.texi | |
parent | 80fdeb4e5a869726da90c88ddce377f599515ee8 (diff) | |
download | guile-a0e07ba4ec86e4df014fee0666f18ece5a4d2471.tar.gz |
* Organize documentation into per-manual directories (halfway point commit).
Diffstat (limited to 'doc/tutorial/guile-tut.texi')
-rw-r--r-- | doc/tutorial/guile-tut.texi | 1334 |
1 files changed, 1334 insertions, 0 deletions
diff --git a/doc/tutorial/guile-tut.texi b/doc/tutorial/guile-tut.texi new file mode 100644 index 000000000..b300e2efa --- /dev/null +++ b/doc/tutorial/guile-tut.texi @@ -0,0 +1,1334 @@ +\input texinfo @c -*-texinfo-*- +@c %**start of header +@setfilename guile-tut.info +@settitle Guile Tutorial +@set guile-tut + +@include version-tutorial.texi + +@dircategory The Algorithmic Language Scheme +@direntry +* Guile Tutorial: (guile-tut). The Guile tutorial. +@end direntry + +@setchapternewpage off +@c Choices for setchapternewpage are {on,off,odd}. +@paragraphindent 2 +@c %**end of header + +@iftex +@finalout +@c DL: lose the egregious vertical whitespace, esp. around examples +@c but paras in @defun-like things don't have parindent +@parskip 4pt plus 1pt +@end iftex + +@titlepage +@title Guile Tutorial +@subtitle For use with Guile @value{VERSION} +@subtitle Last updated @value{UPDATED} +@include AUTHORS + +@page +@vskip 0pt plus 1filll +Copyright @copyright{} 1997, 1998 Free Software Foundation + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the entire +resulting derived work is distributed under the terms of a permission +notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions, +except that this permission notice may be stated in a translation approved +by the author. +@end titlepage + + +@ifinfo +@node Top +@top Guile Tutorial +@end ifinfo + +@ifinfo +This file gives a tutorial introductionto Guile. + +Copyright (C) 1997 Free Software Foundation + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +@ignore +Permission is granted to process this file through TeX and print the +results, provided the printed document carries copying permission +notice identical to this one except for the removal of this paragraph +(this paragraph not being relevant to the printed manual). + +@end ignore +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the entire +resulting derived work is distributed under the terms of a permission +notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions, +except that this permission notice may be stated in a translation approved +by the author. +@end ifinfo + + +@menu +* Jump Start:: +* Introduction:: +* Using Guile to program in Scheme:: +* Guile in a Library:: +* Regular Expression Support:: +* UNIX System Programming:: +* Where to find more Guile/Scheme resources:: +* Concept Index:: +* Procedure and Macro Index:: +* Variable Index:: +* Type Index:: +@end menu + +@node Jump Start +@chapter Jump Start + +@noindent +Before giving an overview of Guile, I present some simple commands and +programs that you can type to get going immediately. + +Start by invoking the Guile interpreter (usually you do this by just +typing @code{guile}). Then type (or paste) the following expressions at +the prompt; the interpreter's response is preceded (in this manual) by +@result{}. + +@example +<shell-prompt> guile +@end example +@lisp +(+ 20 35) +@result{} 55 +(define (recursive-factorial n) + (if (= n 0) + 1 + (* n (recursive-factorial (- n 1))))) +(recursive-factorial 5) +@result{} 120 +(recursive-factorial 500) +@result{} 1220136825991110068701238785423046926253574342803192842192413588 + 3858453731538819976054964475022032818630136164771482035841633787 + 2207817720048078520515932928547790757193933060377296085908627042 + 9174547882424912726344305670173270769461062802310452644218878789 + 4657547771498634943677810376442740338273653974713864778784954384 + 8959553753799042324106127132698432774571554630997720278101456108 + 1188373709531016356324432987029563896628911658974769572087926928 + 8712817800702651745077684107196243903943225364226052349458501299 + 1857150124870696156814162535905669342381300885624924689156412677 + 5654481886506593847951775360894005745238940335798476363944905313 + 0623237490664450488246650759467358620746379251842004593696929810 + 2226397195259719094521782333175693458150855233282076282002340262 + 6907898342451712006207714640979456116127629145951237229913340169 + 5523638509428855920187274337951730145863575708283557801587354327 + 6888868012039988238470215146760544540766353598417443048012893831 + 3896881639487469658817504506926365338175055478128640000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000000 +<control-D> +@end lisp + +In this example we did some simple arithmetic @code{(+ 20 35)} and got +the answer @code{55}. Then we coded the classic (and rather wasteful) +factorial algorithm, and got a glimpse of Scheme's nice +@emph{bignumbers} by asking for the factorial of 1000. Then we quit +with @code{(quit)}. +@cindex bignumbers + +This is the most basic use of Guile: a simple Scheme interpreter. In +the rest of this tutorial I will show you how Guile has many facets: it +is also an @emph{extensible} interpreter (to which many features can be +easilly added) and an @emph{embeddable} interpreter (which can be +invoked from your C programs). + + +@node Introduction +@chapter Introduction + +@noindent +@dfn{Guile} (which can stand for @emph{GNU Ubiquitous Intelligent +Language Extension}) is the GNU extension language. It started out as +an embeddable Scheme interpreter, and has rapidly evolved into a +kitchen-sink package including a standalone Scheme interpreter, an +embeddable Scheme interpreter, several graphics options, other languages +that can be used along with Scheme (for now just @emph{ctax} and +@emph{Tcl}), and hooks for much more. + + +@menu +* What are scripting and extension languages:: +* History of Guile and its motivations:: +* How to characterize Guile:: +@end menu + +@node What are scripting and extension languages +@section What are scripting and extension languages +@cindex scripting languages +@cindex extension languages + +A @dfn{scripting language} is a programming language which serves as +glue between other system programs. In the UNIX world, the traditional +scripting language is the @emph{Bourne shell}, which allows many UNIX +commands to be executed in sequence, or in a pipeline. Traditional UNIX +commands are cleverly written to work well when put together in a +script. + +Other examples of UNIX scripting languages are AWK, Perl, Scsh (the +Scheme Shell: a Scheme interpreter enhanced to do good scripting), +Python, Tcl, Java @dots{} +@cindex scripting languages - examples + +UNIX programmers noticed, more than 25 years ago, that scripting +languages can do serious work, so the Bourne shell was written to have +variables, operators and control structures, just like a full-featured +programming language. +@cindex Bourne shell + +What scripting languages have, that traditional programming languages do +not, is the ability to easily run an external program (or a pipeline of +external programs) and use the returned values and output from that +program in useful ways. + +An @dfn{extension language} is a programming language interpreter +offered by an application program, so that users can write macros or +even full-fledged programs to extend the original application. +Extension languages have a C interface (it is usually C, but it could be +any other compiled language), and can be given access to the C data +structures. Likewise, there are C routines to access the extension +language data structures. + +Extension languages abound in the software world, even though the name +@emph{extension language} is seldom used. Examples are: +@cindex extension languages - examples + +@itemize @bullet +@item +Emacs Lisp, the language used to program and customize GNU Emacs. +@cindex Emacs Lisp + +@item +Tcl, John Ousterhout's general-purpose scripting and extension language. +@cindex Tcl + +@item +The Lotus 1-2-3 macro language (any spreadsheet macro language, +really). I mention this one first because it is a classic, even though +it is seldom used any more. +@cindex Lotus 1-2-3 + +@item +Other spreadsheet and database macro languages. + +@item +The Dominion empire-style game's @emph{exec} files. +@cindex Dominion + +@item +Any syntax for a ".*rc" file you might have used. Almost all programs +end up parsing some kind of startup or configuration file. The syntax +for those can get pretty involved, thus justifying calling them +"extension languages". The @emph{fvwm} window manager, for example, +parses a rather elaborate @file{.fvwmrc} file. + +@item +Brent Benson's libscheme.a, an embeddable Scheme interpreter. +@cindex Benson, Brent +@cindex libscheme + +@item +Guile, the GNU extension language, which is the subject of this +tutorial. + +@end itemize + +One lesson we can learn from looking at classical large software +applications is that "writers of large programs" always end up throwing +in some kind of parser for configuration or scripting. + +Of the examples listed above, Emacs Lisp, Tcl, Libscheme and Guile have +an important property: they are not added as an afterthought for a +specific application. They are general-purpose languages which a user +can learn (even in college courses) and then use to customize the +application program. + +This is a recent and (in my opinion) very exciting direction in +large-program software engineering: program designers can link in the +Guile or Tcl library from the very beginning, and tell their users "You +want to customize this program? Just use Scheme (or Tcl, or whatever +language), which you already know!" +@cindex large programs + + +@node History of Guile and its motivations +@section History of Guile and its motivations + +A few separate threads of events led to the development of Guile. + +In the fall of 1994, Richard Stallman, director of the GNU project, +posted an article with the subject "Why you should not use Tcl", in +which he argued that Tcl is inadequate as an extension language. This +generated a flurry of flames (available in the hypermail archive +(@url{http://www.utdallas.edu/acc/glv/Tcl/war/}) @strong{The Tcl War}). +@cindex Stallman, Richard +@cindex GNU project +@cindex Tcl + +The result was that Stallman then proposed his design for the GNU +Extension Language, first called GEL and then renamed Guile. The +discussion triggered by that article is also available in a hypermail +archive, @url{http://www.utdallas.edu/acc/glv/Tcl/war2/}. + +One interesting feature of this GNU Extension Language plan was that +users should have a @emph{choice} of languages to use in extending their +program. The basic language would be a slightly modified Scheme, and +translators would be written to convert other languages (like Tcl, +Python, Perl, C-like languages @dots{}) into Scheme. + +Tom Lord started working on this project immediately, taking Aubrey +Jaffer's small and portable implementation of Scheme, SCM, and making it +into an embeddable interpreter: callable from C and allowing new Scheme +procedures to be written in C. +@cindex Lord, Tom +@cindex Jaffer, Aubrey + +In the spring of 1995, the guile-ii snapshot was released. This made it +possible to start writing code in C and Scheme using the guile +facilities. + +The guile-iii snapshot was released the summer of 1995, and it had fixed +enough problems so that the access to Scheme data structures from C was +almost complete. + +After this, Cygnus Support added many features to Guile and finished +implementing others, so that Guile acquired thread support, a regular +expression matcher, a Tk interface, an interface to the SGI OpenGL +graphics system, an @emph{applet} formalism, and some other packages. +This was all in the Cygnus Guile r0.3 and r0.4 releases. +@cindex Cygnus Support + +Meanwhile, Tom Lord left the project after having produced a divergent +version of Guile: 1.0b2. The Free Software Foundation hired Jim Blandy +to coordinate Guile development. The FSF released its first version of +Guile in January 1997. In the future, many of the Cygnus packages will +be re-integrated into Guile. +@cindex Blandy, Jim +@cindex Free Software Foundation + + + +@node How to characterize Guile +@section How to characterize Guile + +I have already mentioned that Guile has become a kitchen sink package; +here you can see how Guile freely takes new commands and constructs from +the portable Scheme library @emph{slib}, the @emph{Tk} widget set, a +posix library (useful for UNIX systems programming), the regular +expression library @emph{rx}, and many more @dots{} +@cindex slib +@cindex Tk +@cindex POSIX +@c @cindex OpenGL +@cindex rx + +So Guile has many more primitive procedures available to it than those +specified in @ref{Standard Procedures, Revised(5) Report on the +Algorithmic Language Scheme, , r5rs, Revised(5) Report on the +Algorithmic Language Scheme}. On top of that, Guile will interpret +almost all standard Scheme programs. The only incompatible difference +between the basic Guile language and R5RS Scheme is that Guile is case +sensitive, whereas R5RS is case insensitive. We hope that few people +have written Scheme programs that depend on case insensitivity. +@cindex case sensitivity +@cindex Revised(5) Report on the Algorithmic Language Scheme +@cindex report on Scheme +@cindex Scheme language - report +@cindex Scheme language - definition + +Here is a possible view of the @emph{sum of the parts} in Guile: +@cindex extensions to standard Scheme +@cindex extensions to R5RS +@cindex Scheme extensions +@example +guile = standard Scheme (R5RS) + PLUS extensions to R5RS offered by SCM + PLUS some extra primitives offered by Guile (catch/throw) + PLUS portable Scheme library (SLIB) + PLUS embeddable Scheme interpreter library (libguile) + PLUS Tk toolkit + PLUS threads + PLUS Posix library +@c PLUS OpenGL library (mesa) +@c PLUS OpenGL toolkit (glut) + PLUS Regular expression library (rx) +@c PLUS Applet formalism + PLUS Tcl library +@end example + + +@node Using Guile to program in Scheme +@chapter Using Guile to program in Scheme +@cindex Scheme programming tutorial +@cindex tutorial on Scheme programming + +In this section I give a tutorial introduction to programming in Scheme, +with a slant toward the interesting things that can be done in Guile. + +@c Applets are so @emph{chic} that they get their own section, but this +This section will try to touch on many of the interesting and cool +aspects of Guile, showing you how new types of problems can be solved +with Guile. Note that using Guile as a library with @code{libguile.a} +is described in its own chapter (@pxref{Guile in a Library}). Also note +that some small examples are given in @ref{Jump Start}. + +To get started you need to know how to program in @dfn{Scheme} (a +dialect of LISP). Fortunately Scheme is a small, clean language and is +not hard to learn. It is also used in many undergraduate courses to +introduce computer programming. +@cindex lisp dialects + +I will not try to teach you Scheme here (although you might end up +learning by example), since there are many good books on the subject, +listed in @ref{Where to find more Guile/Scheme resources}. @footnote{To +get started, look at the books @cite{Simply Scheme} and @cite{The Little +Schemer} from that list.} + + +@subsection Hello World +@cindex hello world + +Our first program is the typical Scheme "hello world" program. Put the +following code in a file called @code{hello.scm} (this can be find in +@file{examples/scheme/hello.scm}). + +@smalllisp +#!/usr/local/bin/guile -s +!# + +(display "hello world") +(newline) +@end smalllisp + +Then run guile on it. One way to do so is to start up guile and load +this file: + +@smallexample +<shell-prompt> @kbd{guile} +guile> @kbd{(load "hello")} +@end smallexample + +Another way is to make the file executable and execute it directly. +Notice how Guile recognizes a @code{-s} option which tells it to run a +script and then exit. Guile also has a new type of block comment +enclosed by @code{#!} and @code{!#}, so that you can make executable +Scheme scripts with the standard UNIX @code{#!} mechanism. + +In the given example, the first line is used to invoke the Guile +interpreter (make sure you correct the path if you installed Guile in +something other than /usr/local/bin). Once Guile is invoked on this +file, it will understand that the first line is a comment. The comment +is then terminated with @code{!#} on the second line so as to not +interfere with the execution mechanism. + + +@subsection A bunch of operations in Scheme + +Here is some code you can type at the @code{guile>} prompt to see some +of the Scheme data types at work (mostly lists and vectors). I have +inserted brief comments @emph{before} each line of code explaining what +happens. + +@smalllisp +;; @r{make a list and bind it to the symbol @code{ls}} +guile> @kbd{(define ls (list 1 2 3 4 5 6 7))} + @result{} +;; @r{display the list} +guile> @kbd{ls} + @result{(1 2 3 4 5 6 7)} +;; @r{ask if @code{ls} is a vector; @code{#f} means it is not} +guile> @kbd{(vector? ls)} + @result{#f} +;; @r{ask if @code{ls} is a list; @code{#t} means it is} +guile> @kbd{(list? ls)} + @result{#t} +;; @r{ask for the length of @code{ls}} +guile> @kbd{(length ls)} + @result{7} +;; @r{pick out the first element of the list} +guile> @kbd{(car ls)} + @result{1} +;; @r{pick the rest of the list without the first element} +guile> @kbd{(cdr ls)} + @result{(2 3 4 5 6 7} +;; @r{this should pick out the 3rd element of the list} +guile> @kbd{(car (cdr (cdr ls)))} + @result{3} +;; @r{a shorthand for doing the same thing} +guile> @kbd{(caddr ls)} + @result{3} +;; @r{append the given list onto @code{ls}, print the result} +;; @r{@strong{NOTE:} the original list @code{ls} is @emph{not} modified} +guile> @kbd{(append ls (list 8 9 10))} + @result{(1 2 3 4 5 6 7 8 9 10)} +guile> @kbd{(reverse ls)} + @result{(10 9 8 7 6 5 4 3 2 1)} +;; @r{ask if 12 is in the list --- it obviously is not} +guile> @kbd{(memq 12 ls)} + @result{#f} +;; @r{ask if 4 is in the list --- returns the list from 4 on.} +;; @r{Notice that the result will behave as true in conditionals} +guile> @kbd{(memq 4 ls)} + @result{(4 5 6 7)} +;; @r{an @code{if} statement using the aforementioned result} +guile> @kbd{(if (memq 4 ls) + (display "hey, it's true!\n") + (display "dude, it's false\n"))} + @print{hey, it's true!} + @result{} +guile> @kbd{(if (memq 12 ls) + (display "hey, it's true!\n") + (display "dude, it's false\n"))} + @print{dude, it's false} + @result{} +guile> @kbd{(memq 4 (reverse ls))} + @result{(4 3 2 1)} +;; @r{make a smaller list @code{ls2} to work with} +guile> @kbd{(define ls2 (list 2 3 4))} +;; @r{make a list in which the function @code{sin} has been} +;; @r{applied to all elements of @code{ls2}} +guile> @kbd{(map sin ls2)} + @result{(0.909297426825682 0.141120008059867 -0.756802495307928)} +;; @r{make a list in which the squaring function has been} +;; @r{applied to all elements of @code{ls}} +guile> @kbd{(map (lambda (n) (expt n n)) ls)} + @result{(1 4 27 256 3125 46656 823543)} +@end smalllisp + +@smalllisp +;; @r{make a vector and bind it to the symbol @code{v}} +guile> @kbd{(define v #(1 2 3 4 5 6 7))} +guile> @kbd{v} + @result{#(1 2 3 4 5 6 7)} +guile> @kbd{(vector? v)} + @result{#t} +guile> @kbd{(list? v)} + @result{#f} +guile> @kbd{(vector-length v)} + @result{7} +;; @r{vector-ref allows you to pick out elements by index} +guile> @kbd{(vector-ref v 2)} + @result{3} +;; @r{play around with the vector: make it into a list, reverse} +;; @r{the list, go back to a vector and take the second element} +guile> @kbd{(vector-ref (list->vector (reverse (vector->list v))) 2)} + @result{5} +;; @r{this demonstrates that the entries in a vector do not have} +;; @r{to be of uniform type} +guile> @kbd{(vector-set! v 4 "hi there")} + @result{"hi there"} +guile> @kbd{v} + @result{#(1 2 3 4 "hi there" 6 7)} +@end smalllisp + + +@subsection Using recursion to process lists +@cindex recursion +@cindex list processing + +Here are some typical examples of using recursion to process a list. + +@smalllisp +;; @r{this is a rather trivial way of reversing a list} +(define (my-reverse l) + (if (null? l) + l + (append (my-reverse (cdr l)) (list (car l))))) +(my-reverse '(27 32 33 40)) +@result{(40 33 32 27)} +@end smalllisp + + +@subsection Processing matrices + +Suppose you have a matrix represented as a list of lists: + +@smalllisp +(define m + (list + (list 7 2 1 3 2 8 5 3 6) + (list 4 1 1 1 3 8 9 8 1) + (list 5 5 4 8 1 8 2 2 4))) +@end smalllisp + +Then you could apply a certain function to each element of the matrix in +the following manner: +@smalllisp +;; @r{apply the function func to the matrix m element-by-element;} +;; @r{return a matrix with the result.} +(define (process-matrix m func) + (map (lambda (l) + (map func l)) + m)) +@end smalllisp +Notice that I have used the Scheme @code{map} procedure because I am +interested in the matrix that results from the application of +@code{func}, rather than in the side effects associated with applying +@code{func}. + +This could be invoked with @code{(process-matrix m sin)} or +@code{(process-matrix m (lambda (x) (* x x)))}; for example: + +@smalllisp +(process-matrix m (lambda (x) (* x x))) +@result{((49 4 1 9 4 64 25 9 36) (16 1 1 1 9 64 81 64 1) (25 25 16 64 1 64 4 4 16))} +@end smalllisp + +To print a representation of the matrix, we could define a generalized +routine: +@smalllisp +;; @r{proc is a procedure to represent the single element,} +;; @r{row-proc is a procedure that is invoked after each row.} +;; @r{Example: proc could be (lambda (x) (begin (display x) (display " ")))} +;; @r{and row-proc could be (lambda (l) (display "\n"))} +(define (represent-matrix m proc row-proc) + (for-each (lambda (l) + (begin + (for-each proc l) + (row-proc l))) + m)) +@end smalllisp +@findex represent-matrix + +And then invoke it with +@smalllisp +(represent-matrix m + (lambda (x) (begin (display x) (display " "))) + (lambda (l) (begin (display "\n")))) +@print{7 2 1 3 2 8 5 3 6} +@print{4 1 1 1 3 8 9 8 1} +@print{5 5 4 8 1 8 2 2 4} +@end smalllisp + +@cindex objects + +Now we write a helper routine that uses Scheme @dfn{closures} to make +objects with state that then receive messages to draw little squares. +@cindex closures +@cindex syntactic closures + +But let us take it one step at a time. I will start by showing you a +simple example of object in Scheme. The object I make here represents a +cell, which could be a cell in a matrix. The cell responds to commands +to draw itself, to return the next cell, and so forth. @emph{Guile does +not currently have a Tk interface, so I will leave the hooks for +graphical rendering. In a future release of Guile I will add graphical +rendering messages to the cell object.} + +@smallexample +;; @r{cell-object.scm: routines for creating and manipulating cell objects} + +;; @r{(the-x, the-y) is the initial position of the cell.} +;; @r{the-color is a string representing a color; must be something Tk can grok.} +;; @r{square-size is the size of the square that gets drawn.} +;; @r{(sizex, sizey) is the size of the matrix.} +(define (MAKE-CELL the-x the-y the-color square-size sizex sizey) + (define (get-x) the-x) + (define (get-y) the-y) + + (define (set-x! new-x) + (set! the-x new-x) + the-x) + (define (set-y! new-y) + (set! the-y new-y) + the-y) + (define (get-color) the-color) + (define (set-color! new-color) + (set! the-color new-color) + the-color) + (define (next!) + (set! the-x (+ the-x 1)) + (if (>= the-x sizex) + (begin + (set! the-x 0) + (set! the-y (+ the-y 1)))) + (if (>= the-y sizey) + (begin + (display "CELL next!: value of y is too big; not changing it\n") + (set! the-y (- the-y 1)))) + (cons the-x the-y)) + (define (draw) + (let* ((x0 (* the-x square-size)) + (y0 (* the-y square-size)) + (x1 (+ x0 square-size)) + (y1 (+ y0 square-size))) + (display "I should draw a ") + (display the-color) + (display " rectangle with corners at ") + (display x0) (display y0) (display x1) (display y1) + )) + + ;; self is the dispatch procedure + (define (self message) + (case message + ((x) get-x) + ((y) get-y) + ((set-x!) set-x!) + ((set-y!) set-y!) + ((color) get-color) + ((set-color!) set-color!) + ((next!) next!) + ((draw) draw) + (else (error "CELL: Unknown message -> " message)))) + ;; and now return the dispatch procedure + self + ) +@end smallexample +@cindex cell-object +@findex MAKE-CELL + +What does this procedure do? It returns another procedure +(@code{self}) which receives a message (x, y, set-x!, set-y!, @dots{}) +and takes an action to return or modify its state. The state consists +of the values of variables @code{the-x}, @code{the-y}, @code{the-color} +and so forth. + +Here are some examples of how to use MAKE-CELL and the cell object it +creates: +@smallexample +(define c (MAKE-CELL 0 0 "red" 10 7 9)) + +;; @r{retrieve the x and y coordinates} +((c 'x)) +@result{0} +((c 'y)) +@result{0} +;; @r{change the x coordinate} +((c 'set-x!) 5) +@result{5} +((c 'x)) +@result{5} +;; @r{change the color} +((c 'color)) +@result{"red"} +((c 'set-color!) "green") +@result{"green"} +((c 'color)) +@result{"green"} +;; @r{now use the next! message to move to the next cell} +((c 'next!)) +@result{(6 . 0)} +((c 'x)) +@result{6} +((c 'y)) +@result{0} +;; @r{now make things wrap around} +((c 'next!)) +@result{(0 . 1)} +((c 'next!)) +@result{(1 . 1)} +((c 'next!)) +@result{(2 . 1)} +((c 'x)) +@result{2} +((c 'y)) +@result{1} +@end smallexample + +You will notice that expressions like @code{(c 'next)} return procedures +that do the job, so we have to use extra parentheses to make the job +happen. This syntax is rather awkward; one way around it is to define a +@code{send} procedure: + +@smallexample +;; @r{send makes object syntax a bit easier; instead of saying} +;; @r{ ((my-cell 'set-x!) 4)} +;; @r{you can say} +;; @r{ (send my-cell 'set-x! 4)} +(define (send obj . args) + (let ((first-eval (apply obj (list (car args))))) + (if (null? (cdr args)) + (first-eval) + (apply first-eval (cdr args))))) +@end smallexample +@findex send + +You can see that @code{send} passes the message to the object, making +sure that things are evaluated the proper number of times. You can now +type: + +@smallexample +(define c2 (MAKE-CELL 0 0 "red" 10 7 9)) +(send c2 'x) +@result{0} +(send c2 'set-x! 5) +@result{5} +(send c2 'color) +@result{"red"} +(send c2 'set-color! "green") +@result{"green"} +(send c2 'next!) +@result{(1 . 0)} +(send c2 'x) +@result{1} +(send c2 'y) +@result{0} +@end smallexample + +@cindex object-based programming +@cindex object-oriented programming + +This is the simplest way of implementing objects in Scheme, but it does +not really allow for full @emph{object-oriented programming} (for +example, there is no inheritance). But it is useful for +@emph{object-based programming}. + +Guile comes with a couple more complete object-oriented extensions to +Scheme: these are part of slib (@pxref{Object, , , slib, SLIB: the +portable Scheme library} and @pxref{Yasos, , , slib, SLIB: the portable +Scheme library}). + +@node Guile in a Library +@chapter Guile in a Library + +@iftex +@nobreak +@end iftex +In the previous chapters Guile was used to write programs entirely in +Scheme, and no C code was seen; but I have been claiming @emph{ad +nauseam} that Guile is an @emph{extension} language. Here we see how +that is done, and how that can be useful. +@cindex libguile +@cindex extending C programs + + +@menu +* Two world views:: +* What is libguile:: +* How to get started with libguile:: +* More interesting programming with libguile:: +* Further examples:: +@end menu + +@node Two world views +@section Two world views +@cindex master world + +In this manual, I usually jump into examples and explain them as you +type in the code; here I will digress and ramble for a few paragraphs to +set some concepts straight, and then let you type (or paste) in fun +examples. + +In 1995, I implemented a large program, @dfn{Gnudl}, using Guile quite +extensively. In the design phase of Gnudl, I found I had to make a +choice: should the fundamental data structures be C or Scheme data +structures? +@cindex gnudl +@cindex GNU Data Language +@cindex Galassi, Mark + +Guile allows C to see its data structures (scalar types, lists, vectors, +strings @dots{}). C also allows Guile to see its data structures. As a +large program designer, you have to decide which of those capabilities +to use. You have two main choices: + +@enumerate 1 +@item +You can write your software mostly in Scheme. In this case, your C +software will mostly parse the Scheme code with Guile calls, and provide +some new primitive procedures to be used by Scheme. This is what Gnudl +does. + +@item +You can write your software mostly in C, occasionally allowing Scheme +code to be parsed by Guile, either to allow the user to modify data +structures, or to parse a configuration file, @dots{} +@end enumerate + +Mixing the two approaches seems unwise: the overall layout would be +confusing. But who knows? There might be problems that are best solved +by a hybrid approach. Please let me know if you think of such a +problem. + +If you use the former approach, we will say that the @dfn{master world} +is Scheme, and the C routines serve Scheme and access Scheme data +structures. In the latter case, the master world is C, and Scheme +routines serve the C code and access C data structures. + +In both approaches the @code{libguile.a} library is the same, but a +predominantly different set of routines will be used. When we go +through examples of libguile use, we will point out which is the master +world in order to clarify these two approaches. + + +@node What is libguile +@section What is libguile +@cindex libguile +@cindex gh interface +@cindex scm interface + +@dfn{Libguile} is the library which allows C programs to start a Scheme +interpreter and execute Scheme code. There are also facilities in +libguile to make C data structures available to Scheme, and vice versa. + +The interface provided by the libguile C library is somewhat specific to +the implementation of the Scheme interpreter. This low-level libguile +interface is usually referred to as the @code{scm_} interface, since its +public calls (API) all have the @code{scm_} prefix. + +There is also a higher-level libguile interface, which is usually +referred to as the @code{gh_} interface (libGuile High). Its public +calls all have the @code{gh_} prefix. The @code{gh_} library interface +is designed to hide the implementation details, thus making it easier to +assimilate and portable to other underlying Scheme implementations. + +People extending Guile by adding bindings to C libraries (like OpenGL or +Rx) are encouraged to use the @code{gh_} interface, so their work will +be portable to other Scheme systems. The @code{gh_} interface should be +more stable, because it is simpler. + +The @code{scm_} interface is necessary if you want to poke into the +innards of Scheme data structures, or do anything else that is not +offered by the @code{gh_} interface. It is not covered in this +tutorial, but is covered extensively in @ref{Scheme data representation, +Guile Reference Manual, guile-ref, Guile Reference Manual}. + +This chapter gives a gentle introduction to the @code{gh_} interface, +presenting some @emph{hello world}-style programs which I wrote while +teaching myself to use libguile. +@cindex hello world + +The @cite{Guile Programmer's Manual} gives more examples of programs +written using libguile, illustrating diverse applications. You can also +consult my @emph{Gnudl} documentation at +@url{http://nis-www.lanl.gov/~rosalia/mydocs/} to see a large scale +project that uses C and Scheme code together. + + +@node How to get started with libguile +@section How to get started with libguile +@cindex learn0 + +Here is an elementary first program, @code{learn0}, to get going with +libguile. The program (which uses Scheme as a master world) is in a +single source file, @code{learn0.c}: + +@smallexample +/* @r{test the new libgh.a (Guile High-level library) with a trivial + program} */ + +#include <stdio.h> + +#include <guile/gh.h> + +void main_prog(int argc, char *argv[]); + +main(int argc, char *argv[]) +@{ + gh_enter(argc, argv, main_prog); +@} + +void main_prog(int argc, char *argv[]) +@{ + int done; + char input_str[200]; + + gh_eval_str("(display \"hello Guile\")"); + gh_eval_str("(newline)"); + + /* @r{for fun, evaluate some simple Scheme expressions here} */ + gh_eval_str("(define (square x) (* x x))"); + gh_eval_str("(define (fact n) (if (= n 1) 1 (* n (fact (- n 1)))))"); + gh_eval_str("(square 9)"); + + /* @r{now sit in a Scheme eval loop: I input the expressions, have + Guile evaluate them, and then get another expression.} */ + done = 0; + fputs("learn0> ", stdout); + while (fgets(input_str, 199, stdin) != NULL) @{ + gh_eval_str(input_str); + fputs("\nlearn0> ", stdout); + @} + + exit(0); +@} +@end smallexample + +If you name this program @code{learn0.c}, it can now be compiled with: +@smallexample +gcc -g -c learn0.c -o learn0.o +gcc -o learn0 learn0.o -lguile -lm +@end smallexample + +@c @emph{NOTE: If you are in the Guile development tree, you can simply do +@c ``cd doc/examples/c; make; ./learn0''.} + +The program is simple: it creates a Scheme interpreter, passes a couple +of strings to it that define new Scheme functions @code{square} and +@code{factorial}, and then a couple of strings that invoke those +functions. + +It then goes into a read-eval-print-loop (REPL), so you could type +one-line Scheme expressions to it and have them evaluated. For example: +@smallexample +<shell-prompt> ./learn0 +hello Guile +learn0> (display (sin 1.3)) +963.558185417193e-3 +learn0> (display (fact 10)) +3628800 +learn0> (quit) +<shell-prompt> +@end smallexample + +You should notice the key steps involved in this @code{learn0} program: + +@cartouche +@enumerate +@item +@code{#include <guile/gh.h>} +@item +You need to invoke the initialization routine @code{gh_enter()}. This +starts up a Scheme interpreter, handling many implementation-specific +details. +@item +Your main() function should be almost empty: the real main program goes +in a separate function main_prog() which is passed to gh_enter(). This +rather arcane convention is due to the way Guile's garbage collector +works: the whole program has to run in the dynamic context of +@code{gh_enter()}. +@item +You pass strings to the Scheme interpreter with the @code{gh_eval_str()} +routine. +@item +You link your program with @code{-lguile}. +@end enumerate +@end cartouche + + +@node More interesting programming with libguile +@section More interesting programming with libguile +@cindex learn1 +@cindex callback +@cindex builtin functions + +The @code{learn0} program shows how you can invoke Scheme commands from +a C program. This is not such a great achievement: the same could have +been done by opening a pipe to SCM or any other Scheme interpreter. + +A true extension language must allow @dfn{callbacks}. Callbacks allow +you to write C routines that can be invoked as Scheme procedures, thus +adding new primitive procedures to Scheme. This also means that a +Scheme procedure can modify a C data structure. + +Guile allows you to define new Scheme procedures in C, and provides a +mechanism to go back and forth between C and Scheme data types. + +Here is a second program, @code{learn1}, which demonstrates these +features. It is split into three source files: @code{learn1.c}, +@code{c_builtins.h} and @code{c_builtins.c}. I am including the code +here. +@c , but you might just want to look at the online source code and the +@c Makefile.am that come with Guile in the +@c @file{doc/examples/c} directory. + +Notice that @code{learn1} uses a Scheme master world, and the C routines +in @code{c_builtins.c} are simply adding new primitives to Scheme. + +@menu +* learn1.c:: +* c_builtins.h:: +* c_builtins.c:: +* What learn1 is doing:: +* Compiling and running learn1:: +@end menu + +@node learn1.c +@subsection learn1.c + +Here is @file{learn1.c}: +@smallexample +#include <stdio.h> + +#include <guile/gh.h> + +#include "c_builtins.h" + +void main_prog(int argc, char *argv[]); + +main(int argc, char *argv[]) +@{ + gh_enter(argc, argv, main_prog); +@} + +void main_prog(int argc, char *argv[]) +@{ + char input_str[200]; /* @r{ugly hack: assume strlen(line) < 200} */ + int done; + + /* @r{for fun, evaluate some simple Scheme expressions here} */ + gh_eval_str("(define (square x) (* x x))"); + gh_eval_str("(define (fact n) (if (= n 1) 1 (* n (fact (- n 1)))))"); + gh_eval_str("(square 9)"); + gh_eval_str("(fact 100)"); + + /* @r{now try to define some new builtins, coded in C, so that they are + available in Scheme.} */ + gh_new_procedure1_0("c-factorial", c_factorial); + gh_new_procedure1_0("c-sin", c_sin); + gh_new_procedure1_0("v-t", vector_test); + + /* @r{now sit in a Scheme eval loop: I input the expressions, have + Guile evaluate them, and then get another expression.} */ + done = 0; + fputs("learn1> ", stdout); + while (!done) @{ + if (gets(input_str) == NULL) @{ + done = 1; + @} else @{ + gh_eval_str(input_str); + fputs("learn1> ", stdout); + @} + @} + + exit(0); +@} +@end smallexample + +@node c_builtins.h +@subsection c_builtins.h + +Here is @file{c_builtins.h}: +@smallexample +/* @r{builtin function prototypes} */ + +#include <guile/gh.h> + +SCM c_factorial(SCM n); +SCM c_sin(SCM n); +SCM vector_test(SCM s_length); +@end smallexample + +@node c_builtins.c +@subsection c_builtins.c + +Here is @file{c_builtins.c}: +@smallexample +#include <stdio.h> +#include <math.h> + +#include <guile/gh.h> + +#include "c_builtins.h" + +/* @r{this is a factorial routine in C, made to be callable by Scheme} */ +SCM c_factorial(SCM s_n) +@{ + int i; + unsigned long result = 1, n; + + n = gh_scm2ulong(s_n); + + gh_defer_ints(); + for (i = 1; i <= n; ++i) @{ + result = result*i; + @} + gh_allow_ints(); + return gh_ulong2scm(result); +@} + +/* @r{a sin routine in C, callable from Scheme. it is named c_sin() to + distinguish it from the default Scheme sin function} */ +SCM c_sin(SCM s_x) +@{ + double x = gh_scm2double(s_x); + + return gh_double2scm(sin(x)); +@} + +/* @r{play around with vectors in Guile: this routine creates a vector of + the given length, initializes it all to zero except element 2 which + is set to 1.9.} */ +SCM vector_test(SCM s_length) +@{ + SCM xvec; + + c_length = gh_scm2ulong(s_length); + printf("requested length for vector: %ld\n", gh_scm2ulong(s_length)); + + /* create a vector */ + xvec = gh_make_vector(s_length, gh_double2scm(0.0)); + /* set the second element in it */ + gh_vector_set_x(xvec, gh_int2scm(2), gh_double2scm(1.9)); + + return xvec; +@} +@end smallexample + +@node What learn1 is doing +@subsection What learn1 is doing +@cindex registering callbacks +@cindex registering C functions +@cindex primitive procedures + +If you compare learn1 to learn0, you will find that learn1 uses a new +Guile construct: the function @code{gh_new_procedure()}, and its +siblings: + +@smallexample + /* @r{now try to define some new builtins, coded in C, so that they are + available in Scheme.} */ + gh_new_procedure1_0("c-factorial", c_factorial); + gh_new_procedure1_0("c-sin", c_sin); + gh_new_procedure1_0("v-t", vector_test); +@end smallexample + +It is clear that @code{gh_new_procedure()} adds a new builtin +routine written in C which can be invoked from Scheme. We can now +revise our checklist for programming with libguile, so it includes +adding callbacks. +@cindex libguile - step by step + +@cartouche +@enumerate +@item +@code{#include <guile/gh.h>} +@item +You need to invoke the initialization routine @code{gh_enter()}. This +starts up a Scheme interpreter, handling many details. +@item +Your main() function should be almost empty: the real main program goes +in a separate function main_prog() which is passed to gh_enter(). This +rather arcane convention is due to the way Guile's garbage collector +works: the whole program has to run in the dynamic context of +@code{gh_enter()}. +@item +You pass strings to the Scheme interpreter with the @code{gh_eval_str()} +routine. +@item +@strong{[new]} You can now define new builtin Scheme functions; +i.e. define new builtin Scheme functions, with the +@code{gh_new_procedure()} routine. +@item +You pass strings to the Scheme interpreter with the +@code{gh_eval_str()} routine. +@item +You link your program with @code{-lguile}. +@end enumerate +@end cartouche + +I breezed by the issue of how to write your C routines that are +registered to be called from Scheme. This is non-trivial, and is +discussed at length in the @cite{Guile Programmer's Manual}. + + +@node Compiling and running learn1 +@subsection Compiling and running learn1 + +@smallexample +gcc -g -c learn1.c -o learn1.o +gcc -g -c c_builtins.c -o c_builtins.o +gcc -o learn1 learn1.o c_builtins.o -lguile -lm +@end smallexample + +If you run @code{learn1}, it will prompt you for a one-line Scheme +expression, just as @code{learn0} did. The difference is that you can +use the new C builtin procedures (@code{c-factorial}, @code{c-sin}, +@code{v-t}). + +@smallexample +<shell-prompt> ./learn1 +welcome to Guile +hello Guile +learn1> (display (c-factorial 6)) +720 +learn1> (display (c-factorial 20)) +2192834560 +learn1> (display (c-factorial 100)) +0 +learn1> (display (c-sin 1.5)) +0.997494986604054 +learn1> (display (v-t 10)) +requested length for vector: 10 +#(0.0 0.0 1.9 0.0 0.0 0.0 0.0 0.0 0.0 0.0) +learn1> (display (v-t 15)) +requested length for vector: 15 +#(0.0 0.0 1.9 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0) +learn1> (quit) +<shell-prompt> +@end smallexample + +As you see, taking @code{(c-factorial 100)} does not use bignumbers and +returns a bogus answer. + +@node Further examples +@section Further examples + +Further ``idealized'' examples are included in the @code{doc/examples/c} +distribution. They include programs to: + +@c [FIXME: still have to write some of these; then I will revise the list.] + +@itemize @bullet +@item +Parse a startup file (C is the master world). +@item +Set up initial conditions for an n-body simulation (C is the master +world). +@item +Implement a Scheme interpreter with all of Guile's goodies, @emph{plus} +the readline library @emph{and} a fast Fourier transform routine +provided in C (Scheme is the master world). +@end itemize + +@node Regular Expression Support +@chapter Regular Expression Support + +@node UNIX System Programming +@chapter UNIX System Programming + +@node Where to find more Guile/Scheme resources +@chapter Where to find more Guile/Scheme resources + + +@node Concept Index +@unnumbered Concept Index + +@printindex cp + +@node Procedure and Macro Index +@unnumbered Procedure and Macro Index + +This is an alphabetical list of all the procedures and macros in Dominion. + +@printindex fn + +@node Variable Index +@unnumbered Variable Index + +This is an alphabetical list of the major global variables in Dominion. + +@printindex vr + +@node Type Index +@unnumbered Type Index + +This is an alphabetical list of the major data structures in Dominion. + +@printindex tp + +@contents + +@bye |