From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Daniel Kraft Newsgroups: gmane.lisp.guile.devel Subject: Updated Guile Tutorial Date: Thu, 06 Aug 2009 20:34:38 +0200 Message-ID: <4A7B223E.6050501@domob.eu> NNTP-Posting-Host: lo.gmane.org Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="------------010600070300030708070409" X-Trace: ger.gmane.org 1249583724 309 80.91.229.12 (6 Aug 2009 18:35:24 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Thu, 6 Aug 2009 18:35:24 +0000 (UTC) To: guile-devel Original-X-From: guile-devel-bounces+guile-devel=m.gmane.org@gnu.org Thu Aug 06 20:35:16 2009 Return-path: Envelope-to: guile-devel@m.gmane.org Original-Received: from lists.gnu.org ([199.232.76.165]) by lo.gmane.org with esmtp (Exim 4.50) id 1MZ7nN-0001GS-DQ for guile-devel@m.gmane.org; Thu, 06 Aug 2009 20:35:16 +0200 Original-Received: from localhost ([127.0.0.1]:58528 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1MZ7nM-0007Zv-JX for guile-devel@m.gmane.org; Thu, 06 Aug 2009 14:34:32 -0400 Original-Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1MZ7nD-0007XC-21 for guile-devel@gnu.org; Thu, 06 Aug 2009 14:34:23 -0400 Original-Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1MZ7n3-0007RP-Ux for guile-devel@gnu.org; Thu, 06 Aug 2009 14:34:22 -0400 Original-Received: from [199.232.76.173] (port=51407 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1MZ7n3-0007RM-PE for guile-devel@gnu.org; Thu, 06 Aug 2009 14:34:13 -0400 Original-Received: from tatiana.utanet.at ([213.90.36.46]:47130) by monty-python.gnu.org with esmtps (TLS-1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.60) (envelope-from ) id 1MZ7n1-0007OP-PM for guile-devel@gnu.org; Thu, 06 Aug 2009 14:34:13 -0400 Original-Received: from pam.xoc.tele2net.at ([213.90.36.6]) by tatiana.utanet.at with esmtp (Exim 4.69) (envelope-from ) id 1MZ7mt-0000jp-Gu for guile-devel@gnu.org; Thu, 06 Aug 2009 20:34:03 +0200 Original-Received: from dsl-36-208.utaonline.at ([81.189.36.208] helo=[192.168.2.18]) by pam.xoc.tele2net.at with esmtpa (Exim 4.69) (envelope-from ) id 1MZ7mq-000336-Mf for guile-devel@gnu.org; Thu, 06 Aug 2009 20:34:03 +0200 User-Agent: Thunderbird 2.0.0.0 (X11/20070425) X-detected-operating-system: by monty-python.gnu.org: GNU/Linux 2.6 (newer, 3) X-BeenThere: guile-devel@gnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "Developers list for Guile, the GNU extensibility library" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Original-Sender: guile-devel-bounces+guile-devel=m.gmane.org@gnu.org Errors-To: guile-devel-bounces+guile-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.lisp.guile.devel:9037 Archived-At: This is a multi-part message in MIME format. --------------010600070300030708070409 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Hi all, the last days, I worked on a rewrite of the Guile Tutorial (with the Tortoise package); just for fun, but also to update some stuff to my liking and last but not least change the API usage from the deprecated GH routines to the current scm_ ones. All my stuff is attached (I wrote it with TexInfo, but here you also find the converted HTML version for easy browsing). Roughly I based it on the old one, but changed some important points: * Use scm_ routines instead of deprecated GH. * Instead of X (which seems somewhat rough to me) I cooked up some (even more so strange) system to draw with Gnuplot. * As we just have a turtle graphics tool, I added the nice recursive construction of Koch's curve to it. * I left the most advanced stuff out, like executing single Scheme commands or a whole file -- I did skip the final section when reading myself through the original tutorial and think that just pointing to the Manual for further stuff is enough. * Maybe more I don't remember for now... I would like to hear your comments and suggestions on it, and maybe we can work out a real "replacement" for the old one, so that hopefully no new Guile users start with GH ;) Cheers, Daniel -- Done: Arc-Bar-Cav-Ran-Rog-Sam-Tou-Val-Wiz To go: Hea-Kni-Mon-Pri --------------010600070300030708070409 Content-Type: image/png; name="plot1.png" Content-Transfer-Encoding: base64 Content-Disposition: inline; filename="plot1.png" iVBORw0KGgoAAAANSUhEUgAAAawAAAGpCAIAAABeZ5VIAAAAAXNSR0IArs4c6QAABOJJREFU eNrt3M2pwkAUgNF7H6lCa0kD9uDWiizFZlzqXkQQRBCuBbzd4N8k5+wHhzvDR5KFWVUBMFd/ RgCIIIAIAogggAgCiCCACAKIIIAIAogggAgCiCCACAKIIIAIAvRpaFuWmWYH/JqGP0gdPvlj AO/T9nDmdRiYNREERBBABAFEEEAEAUQQQAQBRBBABAFEEEAEAUQQQAQBRBBABAFEEEAEAUQQ QAQBRBBABAFEEEAEAUQQQAQBRBBABAFEEEAEAUQQQAQBRBBABAFEEEAEAUQQQAQBRBBABAFE EEAEAUQQQAQBRBBABAFEEEAEAUQQQAQBRBBABAFEEBBBABEEEEEAEQQQQQARBBBBABEEEEEA EQQQQQARBBBBABEEEEEAEQQQQQARBBBBABEEEEEAEQQQQQARBBBBABEEEEEAEQQQQQARBBBB ABEEEEEAEQQQQQARBBBBABEEEEEAEQQQQQARBBBBABEEEEEAEQQQQQARBBBBABEEEEEAEQRE EEAEAUQQQAQBRBBABAFEEEAEAUQQQAQBRBBABAFEEEAEAUQQQAQBRBBABAFEEEAEAUQQQAQB RBBABAFEEEAEAUQQQAQBRBBABAE+ZTACvmy9jnHsZrf3e+z3sd06t8nIqmpZlo0L4f9lis2m m91er7HbxeXi3H7yKrV0SQT5gQh2dJeOxxjHOByc22Qi6JsgMGsiCIgggAgCiCCACAKIIIAI AogggAgCiCCACAKIIIAIAogggAgCiCCACAKIIIAIAogggAgCiCCACAKIIIAIAogggAgCiCCA CAKIIIAIAogggAgCiCCACAKIIIAIAogggAgCiCCACAKIIIAIAogggAgCiCCACAKIIIAIAogg gAgCiCAgggAiCCCCALMzGAHft1p1s9XbLU4nJyaC8DqLRZzP3ez28Yjl0qFNSVZVy7JsXAjw rpw1dck3QWDWRBAQQQARBBBBABEEEEEAEQQQQQARBBBBABEEEEEAEQQQQQARBBBBABEEEEEA EQQQQQARBBBBABEEEEEAEQQQQQARBBBBABEEEEEAEQQQQQARBBBBABEEEEEAEQQQQQARBBBB ABEEEEEAEQQQQQARBBBBABEEEEEAEQQQQQARBBBBQAQBRBBABAFEEEAEAUQQQAQBRBBABAFE EEAEAUQQQAQBRBBABAFEEEAEAUQQQAQBRBBABAFEEEAEAUQQQAQBRBBABAFEEEAEAUQQQAQB RBBABAFEEEAEAUQQQAQBRBBABAFEEEAEAUQQQAQBRBBABAFEEEAEAUQQQAQBRBBABAFEEBBB ABEEEEEAEQQQQQARBBBBABEEEEEAEQQQQQARBBBBABEEEEEAEQQQQQARBBBBABEEEEEAEQQQ QQARBBBBABEEEEEAEQQQQQARBBBBABEEEEEAEQQQQQARBBBBABEEEEEAEQQQQQARBBBBABEE EEEAEQQQQQARBBBBABEEEEFABI0AEEEAEQQQQQARBBBBABEEEEEAEQQQQQARBBBBABEEEEEA EQQQQQARBBBBABEEEEEAEQQQQQARBBBBABEEEEEAEQQQQQARBBBBABEEEEEAEQQQQQARBBBB ABEEEEGAFxiaV2am8QG9y6oyBcDrMIAIAogggAgCiCCACAKIIIAIAogggAgCiCCACAKIIIAI AnToCVTyROosWVHgAAAAAElFTkSuQmCC --------------010600070300030708070409 Content-Type: image/png; name="plot2.png" Content-Transfer-Encoding: base64 Content-Disposition: inline; filename="plot2.png" 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 B/D/+R+YuCqIrCYbmQAAAABJRU5ErkJggg== --------------010600070300030708070409 Content-Type: image/png; name="plot3.png" Content-Transfer-Encoding: base64 Content-Disposition: inline; filename="plot3.png" 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 jZxPepWf+eOyywDWrAn6D6tX54YbAFauDGh/azik74k3hg8H/OQaf3bvfughX/tY03kHODH6 8uVAGVeZsmZ3qNwe54sWAdx7r3IthKxBJm++GYWhHYW1trw8atcu13dRgF9l27bRrBkXXWSH iFft27N6daCXKjIyOO00Onbkl19K3adbN378MaAubOX8Qrb+PD/frsaqQqGKW0TV2mpE4amy cs1aq8Krw4dZsMDX4N7Zs+nTh2ef9bgefzxrHIKPXFu/ntWradyYjAwyMgD276dePTp3dvb5 6ScKCznhBPvH2FhWrGDrVmeQQwk//EBMDM2a+XkvPvEEwJw5vvb58kt69y51ZeiCAmrUoGbN ynnTP/oowOTJzsiHbdvo0CHkfZKrgn37WLDA7oIOfP0111xD+/asWqVaW4R/C9Wpw+HDJCZy yy2+HqROHXueMh/71KzJ0aN+nkmbNh5jpPbscdbitiqYDRs6UyTl5LB+vZ/nH8jXbKtWpKb6 2mfKFO65h8aN2bnTjd/n11/PvHkeo9asjFMlrqI+IB06OFs2b6ZBA/s+e7TU2qJxbYQRIwyY BQu8/3b7dv9ddc4914DJyPBzoJ49DZi0NO+/XbLEy4GOHPHYYv0/P99LT6KVK311dvU7+iI9 3YDp0MH/+IodO7zvYHU2fvJJt5zWCRMMmA8/VF+0Chi9c8MNEfr0qVpddoPq6mn96vffSz3B e/faXUkr5EBff23AjBnjbO/d24BZs8akpBgwAwY4v3rhBQNm/nz/DxuIxo0NmKwsL7+6/np7 yFSFHMgNp1WqRhlW+WhbvNj78KbERANm3DjnHB85Uq5u91ZVIjGx5PYHHzRgFi/2/mYqrZN3 0ZZvvzVgHnmk5MNag70mTQrouZU2vMEaMmVtHzvWgJk+veQ+1rCHpUvddVqtL4M+fRRQZTRm jAHz6adVIdqivV9bicsH1iUt63UVFFCzZsl9li/n5psZMYIxYyrsQDt3kpDAWWc5/R6//poH HwT417+49lp74zXX8L//sXs3J50U0MMG4vHHGTOGL77wuGhlPUjR/G7HH8gYWrVy6YUt69kW XayUKnbTWV12ISuL2FiaNHHuABYWsnmzR9/rYcOYONFZTgE4cICDB33dGTieNbzp9NOdAQxH j7J9u8dUVr17s3gxp57q/JW15lbRXSpg+3Z69LCXOyh6/k2b2vlb9Pw3b/Z4woG8m2NjndVw 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 RU5ErkJggg== --------------010600070300030708070409 Content-Type: text/html; charset=US-ASCII; name="tutorial.html" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="tutorial.html" Tutorial Introduction to Guile: Top
[Top] [Contents] [Index] [ ? ]

Tutorial Introduction to Guile

This document is an introduction into using Guile, the GNU extension language and system. Guile is a dialect of the Scheme programming language, and I will assume you're at least confident about the very basics of Scheme or LISP in general. However, Guile also allows application developers to integrate it into their code to provide scripting capability to it and extend the main Guile language with primitives specific to the application being extended. Exactly this is what I want to give a brief introduction to.

When I myself first wanted to use Guile as an extension language to one of my own private projects, I did so with the help of David Drysdale's "Tutorial Introduction to Guile" which was really helpful to me, many thanks for him for providing this great document! Unfortunatly, even at the time I got started with it, the API used therein to extend Guile was already deprecated for some time and should not be used any more - but I didn't know that at first, and went to change my code later on.

This document is meant to be a rework of his tutorial to fix mainly this issue; I did, however, rewrite it completely, and thus also some other points have changed according to my discretion - I hope to further clarify things and make them "better", but well, that's my opinion about my own document, so don't count on it. Still, I mainly reused the original structure and borrowed a lot of what I liked best about the original document.

If you want to develop and test the code presented here on-the-fly for yourself while working through the text (it is for sure a good idea and even better if you want to play around with certain stuff not literally presented inbetween), you need of course to install GNU Guile (including the appropriate development package containing header files, if necessary for your system) as well as Gnuplot, and have a UNIX-like environment and some C compiler (just use gcc). I worked on a GNU/Linux machine with Guile 1.8.7, Gnuplot 4.2 and gcc 4.3.1, but any recent Guile and Gnuplot should do it.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

1. The Fundamentals

Guile is an implementation and dialect of the Scheme programming language (Scheme is a dialect of LISP itself), intended to be used as the extension language of the GNU project.

That means, that Guile is designed as a library you can include into your own project and make the interpreter run code within it; additionally, you can provide special procedures in this Guile environment that interface to the core of your application and thus allow manipulating stuff with Scheme scripts a user can write.

The point of this all is to provide an easy way for you to make your application extensible and scriptable. For instance, if you need some sort of configuration files or even real scripting support for your application, you can use Guile instead of rolling your own "small" configuration or scripting language and interpreter; it already exists, so don't waste your time on yet another one but instead keep working on the new and exciting parts of your project! Having Guile as some "universal" scripting language (at least that's what the Guile people would like it to be, but I think it's suited to this goal) also means that a user does not have to learn different languages for each application she wants to configure or script, but instead can do so on all her favourite software with just learning Scheme. Besides, at least my personal opinion is that Scheme is very nice and fun to program in, and very well suited to small pieces of code like scripts.

And the very best: The current development on Guile allows the core Guile "platform" to run not only Scheme code but support other languages as well on top of Guile. So you can just integrate Guile as scripting interpreter into your code, and have it also run scripts in ECMAScript, Emacs Lisp or any other language that Guile will implement in the future (like Perl, Tcl, Python or others) - and you don't have to think a single instant about this!

In concrete terms, installing Guile on your system provides basically two things for you:

First, you can use the guile command-line utility as a Scheme interpreter to write programs (or as a table-top calculator if you want to).

Second, use the libguile programming library to run applications using Guile as scripting extension; or write your own that can access the interpreter and make use of it to script your code.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2. The Tortoise

"Why did you call him Tortoise, if he wasn't one?" Alice asked.

"We called him Tortoise because he taught us," said the Mock Turtle angrily.

(Lewis Carroll, Alice's Adventures in Wonderland)

As the project to demonstrate Guile, we're going to develop a very simple "Turle" graphics program. It will use Gnuplot for graphics output, but should be easy to adapt to any other graphics systems.

It will produce graphics output by assuming that there's a tortoise sitting in the middle of the screen; this tortoise is able to perform some basic instructions given by the user.

You can ask it to turn left by a certain number of degrees (or right by giving a negative number), or you can ask it to walk a certain number of steps forward. It has got a pen and you can ask it to carry it either in its paws or behind its ear, so that when it moves it will leave a mark on the ground or not.

Finally, if you got yourself and the poor tortoise completely confused, you can ask it to walk away to a fresh (empty) ground, sit in the middle and face right, just as at the very start.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.1 The Core System

Let's finally start and implement the core program that will keep track of the tortoise, its movements and the graphics output. This will be implemented in C. As mentioned before, I'm going to use Gnuplot for the graphics output (at first I wanted to use the Gtk+ toolkit, but there were some problems with this approach I will come back to later).

The idea is to start a Gnuplot process in the background and send it commands to draw the lines we want on the screen over a pipe. Here's the code for a program that will start up a Gnuplot process and keep connected to it via a pipe ready to get further plotting commands:

/* Simple backend for a Logo like tortoise drawer.  */

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

static const int WIDTH = 10;
static const int HEIGHT = 10;

static FILE*
start_gnuplot ()
{
  FILE* output;
  int pipes[2];
  pid_t pid;

  pipe (pipes);
  pid = fork ();

  if (!pid)
    {
      dup2 (pipes[0], STDIN_FILENO);
      execlp ("gnuplot", NULL);
      return; /* Not reached.  */
    }

  output = fdopen (pipes[1], "w");

  fprintf (output, "set multiplot\n");
  fprintf (output, "set parametric\n");
  fprintf (output, "set xrange [-%d:%d]\n", WIDTH, WIDTH);
  fprintf (output, "set yrange [-%d:%d]\n", HEIGHT, HEIGHT);
  fprintf (output, "set size ratio -1\n");
  fprintf (output, "unset xtics\n");
  fprintf (output, "unset ytics\n");
  fflush (output);

  return output;
}

static FILE* global_output;

int
main (int argc, char* argv[])
{
  global_output = start_gnuplot ();

  return EXIT_SUCCESS;
}

Note that here we're not doing any error checks on the system routines; you shouldn't be doing this yourself, but it keeps this code as simple as possible. As that so far has nothing to do with what you want to read about in this tutorial, I think this should be the best way to go.

What we're doing here is starting a Gnuplot process with the start_gnuplot routine and opening a pipe that can feed commands to it into global_output, so that we are later able to plot lines.

Gnuplot is started with a fixed coordinate range (-10 to 10 in both x and y directions). We're going to use parametric mode so we won't get any problems drawing vertical lines, and multiplot mode in order to allow building the graphics incrementally by adding single lines each at a time.

Now, this code adds a routine for plotting a line from (x1, y1) to (x2, y2):

static void
draw_line (FILE* output, double x1, double y1, double x2, double y2)
{
  fprintf (output, "plot [0:1] %f + %f * t, %f + %f * t notitle\n",
           x1, x2 - x1, y1, y2 - y1);
  fflush (output);
}

(You may want to read up on parametric plotting in Gnuplot or on parametric equations for lines if you're not sure what's going on here. Or just believe me that this will do what we want for the moment.)

Finally, we can write the routines that will control the tortoise; here's some trigonometry involved, and you will need to #include <math.h>:

static double x, y;
static double direction;
static int pendown;

static void
tortoise_reset ()
{
  x = y = 0.0;
  direction = 0.0;
  pendown = 1;

  fprintf (global_output, "clear\n");
  fflush (global_output);
}

static void
tortoise_pendown ()
{
  pendown = 1;
}

static void
tortoise_penup ()
{
  pendown = 0;
}

static void
tortoise_turn (double degrees)
{
  direction += M_PI / 180.0 * degrees;
}

static void
tortoise_move (double length)
{
  double newX, newY;

  newX = x + length * cos (direction);
  newY = y + length * sin (direction);

  if (pendown)
    draw_line (global_output, x, y, newX, newY);

  x = newX;
  y = newY;
}

That's it, just add a tortoise_reset (); call to the main routine after starting Gnuplot, so that the tortoise starts at a well-defined position.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.2 Testing it out

Of course you want to try it now, don't you? At least I'm burning with excitement... So, we're going to give the tortoise actually some instructions, directly via C code in the main routine:

{
  int i;
  tortoise_pendown (); /* This is unnecessary, but makes it clearer.  */
  for (i = 1; i <= 4; ++i)
    {
      tortoise_move (3.0);
      tortoise_turn (90.0);
    }
}

As a side-note: This program leaves the Gnuplot process alive when terminating; we could send it a quit command before finishing, but later on we won't be able to do so and instead of cooking up anything more complicated, I'll just leave it like that. It basically works like that and even has the advantage that the Gnuplot window stays open until you close it, despite the fact that our tortoise-program has already finished. And if you get worried about the processes, just do a killall gnuplot afterwards...

I don't know about you, but I myself like using Makefiles; so save the full code we've worked out to `tortoise.c' and this as `Makefile':

# Basic Makefile for the tortoise package.

CFLAGS =
LIBS =

.PHONY: clean build run

build: tortoise

clean:
	rm -f tortoise tortoise.o

run: tortoise
	./tortoise

tortoise: tortoise.o
	gcc $< -o $@ $(LIBS)

tortoise.o: tortoise.c
	gcc -c $< -o $@ $(CFLAGS)

Of course, CFLAGS and LIBS are quite useless at the moment, but they will get some use later, so I just included them right away. Now, doing a make run should compile and run your code and open up a Gnuplot window with the resulting graphics; for me it looks like this:

plot1

Congratulations, you've just done your first tortoise-graphics! Still, we don't want to fix and compile the instructions directly with our C code as we just did; instead, the user should be able to interactively control the tortoise.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

3. Becoming Guiled

This is where Guile comes into play. Without it, we could write some additional code that reads, parses and interprets commands to the tortoise, calling the appropriate tortoise primitives as already defined.

Sounds not too bad? Well, probably it isn't. But in the C code we also used a loop to draw the square - otherwise we would have had to repeat the same two lines (movement and turn) four times. And what if we wanted to draw a polygon with, say, 1024 vertices? I hope you are convinced now that to make our tool really useful, we also needed to implement some means of looping.

Hm, while we're at it: Our tortoise-package can also be used to build up a Koch's curve quite elegantly using recursion (try a quick internet search if you can't wait until I'll come back to it in more detail later) - so want to implement some sort of procedures that can recursively call themselves?

All in all, we were probably going to implement a full-fledged tortoise programming language - but think about it: Has this anything to do with our original application and goal? I hate to spoil you all the fun (writing programming languages can be quite fun), but no, it hasn't.

Luckily, we need not go through all this effort; Guile already provides a perfectly good way of making our tortoise programmable. Scheme should be quite a good language to perform all we want (loops, procedures, recursion) - and much more. We just need to link our tortoise to the Guile-world, which will be the topic of the next sections.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

3.1 Adding Guile

First, let's add Guile to our code; you need to #include <libguile.h> as the "master header". In our main routine, take out again the temporary test code we used to produce the first output, and replace it instead by these lines:

scm_with_guile (&register_functions, NULL);
scm_shell (argc, argv);

scm_with_guile may be a bit weird at first glance; what it does is calling the provided routine (register_functions - we'll create it in a few moments), but it also "activates" Guile during this call, so that other Guile library functions can be called from within register_functions. Don't worry about what exactly goes on there, you just need to remember that this indirection is necessary if you want to work with Guile.

(As a side-note: There's also a scm_init_guile method that does this "activation" directly and without this peculiar call-back; it may seem more reasonable and easy-to-understand to you, and you can well use that one instead. However, Guile recommends using scm_with_guile for better portability where possible.)

The call to scm_shell actually runs the Guile REPL (Read-Evaluate-Print Loop, that shell-like command prompt for interactive Scheme evaluation you also get when starting up guile directly) - the idea is to do all the initialization we need for our application, and finally run the REPL, where the user can then enter her commands in Scheme code. Actually, this routine does a little more: It also processes the command-line arguments given to our tortoise-program in the way guile handles its arguments; for instance, you can then do tortoise -s foobar.scm and have your commands read from `foobar.scm'. That's why we need to pass it argc and argv, in case you were interested.

scm_shell does not return, but rather keep on until the user closes the REPL; then our tortoise-program will also finish as a whole. Do you remember that I still owe you an explanation why using the Gtk+ toolkit for graphics would have been more complicated than Gnuplot? The reason I decided against Gtk+ is that for the Gtk+ toolkit, you do something similar: After your program's initialization, you call out to a Gtk+ main loop that will process incoming events and also never fully return control to your program - but in this case, we can't run both Gtk+'s main loop and the Guile REPL; at least not without writing a multi-threaded application, and that would have been again some unnecessary complication; I hope you agree with me now... But if not, just go ahead and try converting our package to Gtk+! I guess that's an interesting exercise.

Finally, we still have to create register_functions:

static void*
register_functions (void* data)
{
  return NULL;
}

You're right, it's not really interesting or even useful for now, but we'll fill it in later. Notice the two void*? The argument data gets passed whatever we want from scm_with_guile - that's why there's NULL as second argument in the call, but we could make it a pointer to an integer or even a large struct in case we needed to pass some data to register_functions. In turn, the return value of register_functions, which is also NULL in this case but could be anything as complex as you want, is returned from scm_with_guile - something we also don't need.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

3.2 Compiling with Guile

Once again, we'll try to compile and run what we have so far. To do so, we have to tell the compiler where to look for `libguile.h' as well as the linker to include libguile. You can work out the appropriate flags for yourself, but the utility guile-config that comes with Guile can do it for you.

So all we need to do is update the Makefile like this (and now the variables get some meaning!):

CFLAGS = `guile-config compile`
LIBS = `guile-config link`

With these adaptions, you should be able to compile and run the program again. This time, the Gnuplot window that pops up should just be empty (and stay so), but on the command-line a Guile REPL will be available just as if you had started guile yourself.

You can do some Scheme programming, but so far nothing to use our little tortoise at all:

guile> (define (foobar a b) (+ a b))
guile> (foobar (* 2 3) 4)
10
guile> (map foobar '(1 2 3) '(4 5 6))
(5 7 9)
guile> (tortoise-reset)

Backtrace:
In current input:
   1: 0* (tortoise-reset)

<unnamed port>:1:1: In expression (tortoise-reset):
<unnamed port>:1:1: Unbound variable: tortoise-reset
ABORT: (unbound-variable)

That's quite nice, isn't it? Still, without control over the tortoise, it does not make sense at all; you can just use guile directly without all the effort we went through in order to program in Scheme. But we can fix this easily.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

3.3 Adding the Tortoise

As I've promised, we'll integrate the tortoise into the Guile environment now. We can simply tell Guile to make our tortoise-procedures available from Scheme with scm_c_define_gsubr; these need to be called from within the activated "Guile mode", so we add the calls to register_functions:

scm_c_define_gsubr ("tortoise-reset", 0, 0, 0, &tortoise_reset);
scm_c_define_gsubr ("tortoise-penup", 0, 0, 0, &tortoise_penup);
scm_c_define_gsubr ("tortoise-pendown", 0, 0, 0, &tortoise_pendown);
scm_c_define_gsubr ("tortoise-turn", 1, 0, 0, &tortoise_turn);
scm_c_define_gsubr ("tortoise-move", 1, 0, 0, &tortoise_move);

The first arguments are the Scheme-names for the procedures we're going to register, the last arguments pointers to the C functions that implement them. The numbers inbetween define the number of arguments the procedures take, namely required, optional and whether there's a rest-list argument nor not - in our case, there are neither optional arguments nor rest-lists, but tortoise-turn and tortoise-move take one required argument (the angle or distance, respectively).

Unfortunatly, this is only one half of the changes needed; Guile represents all Scheme values with the SCM type, and thus both the return values and argument-types of the C procedures need to be SCM's. In order to get the double values out, we need some Guile API functions; our tortoise procedures become:

static SCM
tortoise_reset ()
{
  x = y = 0.0;
  direction = 0.0;
  pendown = 1;

  fprintf (global_output, "clear\n");
  fflush (global_output);

  return SCM_UNSPECIFIED;
}

static SCM
tortoise_pendown ()
{
  SCM result = scm_from_bool (pendown);
  pendown = 1;
  return result;
}

static SCM
tortoise_penup ()
{
  SCM result = scm_from_bool (pendown);
  pendown = 0;
  return result;
}

static SCM
tortoise_turn (SCM degrees)
{
  const double value = scm_to_double (degrees);
  direction += M_PI / 180.0 * value;
  return scm_from_double (direction * 180.0 / M_PI);
}

static SCM
tortoise_move (SCM length)
{
  const double value = scm_to_double (length);
  double newX, newY;

  newX = x + value * cos (direction);
  newY = y + value * sin (direction);

  if (pendown)
    draw_line (global_output, x, y, newX, newY);

  x = newX;
  y = newY;

  return scm_list_2 (scm_from_double (x), scm_from_double (y));
}

You've already guessed it, scm_to_double gets the value "out of" a Scheme number (if it is a number at all, but we won't care about this and assume we're only fed correct arguments).

You also noticed for sure that I made our procedures return some "reasonable" values, using some other Guile API stuff: SCM_UNSPECIFIED means just that there's no return value (like void in C), and if you define a procedure that has no meaningful result, you at least need to return SCM_UNSPECIFIED from it to make Guile happy (and assert this fact).

The penup and pendown commands return (as a Scheme boolean, created by scm_from_bool) the state of the pen before the requested change.

turn and move return the new direction and coordinate (as a Scheme list with two entries), respectively - of course, you already know what scm_from_double and scm_list_2 do, right?

Congratulations, now we've managed to build the whole tortoise package with Guile! And left is all the fun working with it...


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

3.4 Having Fun with our Tortoise

Recompile the program (should be easy thanks to our neat Makefile) and run it. Once again, you should get the Guile (Tortoise!) REPL, but now our procedures should really be available. Try out all of the functionality with a session like this:

guile> (tortoise-move 1)
(1.0 0.0)
guile> (tortoise-turn 90)
90.0
guile> (tortoise-penup)
#t
guile> (tortoise-move 5)
(1.0 5.0)
guile> (tortoise-pendown)
#f
guile> (tortoise-move 1)
(1.0 6.0)
guile> (tortoise-reset)
guile> (tortoise-move (sqrt 2))
(1.4142135623731 0.0)
guile> (quit)

(I won't include the expected graphics output, just see for yourself...) I hope everything works for you, too. If not, it's the perfect time to go back to the code and try to find what's going wrong... Otherwise, let's have some fun and do real programming with our tortoise!

For instance, we can automate the task of drawing polygons with a Scheme function; try out this code:

 
(define (draw-polygon! circumference vertices)
  (let ((side (/ circumference vertices))
        (angle (/ 360 vertices)))
    (let iterate ((i 1))
      (if (<= i vertices)
        (begin
          (tortoise-move side)
          (tortoise-turn angle)
          (iterate (1+ i)))))))

(draw-polygon! 16 4)

(tortoie-penup)
(tortoise-move 1)
(tortoise-turn 30)
(tortoise-pendown)
(draw-polygon! 12 3)

(tortoise-penup)
(tortoise-move -2)
(tortoise-turn -100)
(tortoise-pendown)
(draw-polygon! 10 64)

This is what I get, but try for yourself:

plot2

Remember that I promised you something about Koch's curve? Now we're going to construct it, using a recursive function. See for instance http://en.wikipedia.org/wiki/Koch_curve for details about what Koch's curve is. Anyways, here comes the code; try to find out how it works, if you want:

 
(define (koch-line length depth)
  (if (zero? depth)
    (tortoise-move length)
    (let ((sub-length (/ length 3))
          (sub-depth (1- depth)))
      (for-each (lambda (angle)
                  (koch-line sub-length sub-depth)
                  (tortoise-turn angle))
                '(60 -120 60 0)))))

(define (snowflake length depth sign)
  (let iterate ((i 1))
    (if (<= i 3)
      (begin
        (koch-line length depth)
        (tortoise-turn (* sign -120))
        (iterate (1+ i))))))

(snowflake 8 3 1)
(tortoise-turn 180)
(snowflake 8 3 -1)

Are you impressed? I hope at least a little so... Unfortunatly, the Gnuplot-over-a-pipe approach is quite slow (at least on my system), so you could probably have been even more impressed if the graphics would have been there more quickly; but anyways, at least I like this very much! Regarding the Scheme code, I won't comment it further, as not to spoil all your fun thinking about it. I encourage you to do so, I like this recursive construction very much. Oh, and here's my resulting plot:

plot3

Looks quite interesting, doesn't it? By the way, this is also for me the first time I constructed the "inverse" snowflake with "negative sign" - I don't know if that's done in general, but I just wanted to know the result, so here it is (the left half of the image, which got constructed by the second call).


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4. Next Steps

I hope this introduction so far gave you an idea about what Guile can do for you and how it basically works. For what I needed with my first Guile project, the stuff so far was nearly enough; however, that was of course only the tip of the iceberg, and there's a lot of things you could still learn.

For instance, there are of course a whole lot of other functions in the Guile library to work with Scheme objects; nearly any primitive that is accessible from Scheme can be used from within a C procedure, also - there's even a routine to capture continuations!

Starting up a REPL as we did is nice, but if you just want to run a user's configuration script at start-up of your application and then continue with your code, there are also routines that evaluate single Scheme commands or even run a file and return afterwards.

And if you decided that one tortoise is not enough, you could introduce some sort of "tortoise object" that can be created and passed to the various routines so that a user can control as many tortoises as she wants - such a user-defined Scheme object is called a SMOB in Guile and is of course also easy to realize.

If you ever really need any of the stuff I mentioned or are just curious about what else you can do, I strongly suggest you browse the Guile Reference Manual. Surely you can find all you need (and much more) there! And if you need further help, try asking on the Mailing Lists.

Finally, I hope my write-up was useful to you; in case you have any comments, suggestions, tips or just want to drop me some note whatsoever, I look forward to receiving a message. You can contact me as Daniel Kraft, d@domob.eu. Good luck with Guile and hopefully you also enjoyed reading through this tutorial a little bit!


[Top] [Contents] [Index] [ ? ]

Table of Contents


[Top] [Contents] [Index] [ ? ]

About This Document

This document was generated on August, 6 2009 using texi2html 1.76.

The buttons in the navigation panels have the following meaning:

Button Name Go to From 1.2.3 go to
[ < ] Back previous section in reading order 1.2.2
[ > ] Forward next section in reading order 1.2.4
[ << ] FastBack beginning of this chapter or previous chapter 1
[ Up ] Up up section 1.2
[ >> ] FastForward next chapter 2
[Top] Top cover (top) of document  
[Contents] Contents table of contents  
[Index] Index index  
[ ? ] About about (help)  

where the Example assumes that the current position is at Subsubsection One-Two-Three of a document of the following structure:

  • 1. Section One
    • 1.1 Subsection One-One
      • ...
    • 1.2 Subsection One-Two
      • 1.2.1 Subsubsection One-Two-One
      • 1.2.2 Subsubsection One-Two-Two
      • 1.2.3 Subsubsection One-Two-Three     <== Current Position
      • 1.2.4 Subsubsection One-Two-Four
    • 1.3 Subsection One-Three
      • ...
    • 1.4 Subsection One-Four

This document was generated on August, 6 2009 using texi2html 1.76.

--------------010600070300030708070409 Content-Type: text/plain; name="tutorial.texi" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="tutorial.texi" \input texinfo @c Hello World for Texinfo @setfilename tutorial @settitle Tutorial Introduction to Guile @node Top This document is an introduction into using Guile, the GNU extension language and system. Guile is a dialect of the Scheme programming language, and I will assume you're at least confident about the very basics of Scheme or LISP in general. However, Guile also allows application developers to integrate it into their code to provide scripting capability to it and extend the main Guile language with primitives specific to the application being extended. Exactly this is what I want to give a brief introduction to. When I myself first wanted to use Guile as an extension language to one of my own private projects, I did so with the help of David Drysdale's ``Tutorial Introduction to Guile'' which was really helpful to me, many thanks for him for providing this great document! Unfortunatly, even at the time I got started with it, the API used therein to extend Guile was already deprecated for some time and should not be used any more -- but I didn't know that at first, and went to change my code later on. This document is meant to be a rework of his tutorial to fix mainly this issue; I did, however, rewrite it completely, and thus also some other points have changed according to my discretion -- I hope to further clarify things and make them ``better'', but well, that's my opinion about my own document, so don't count on it. Still, I mainly reused the original structure and borrowed a lot of what I liked best about the original document. If you want to develop and test the code presented here on-the-fly for yourself while working through the text (it is for sure a good idea and even better if you want to play around with certain stuff not literally presented inbetween), you need of course to install GNU Guile (including the appropriate development package containing header files, if necessary for your system) as well as Gnuplot, and have a UNIX-like environment and some C compiler (just use gcc). I worked on a GNU/Linux machine with Guile 1.8.7, Gnuplot 4.2 and gcc 4.3.1, but any recent Guile and Gnuplot should do it. @menu * Fundamentals:: The Fundamentals about Guile. * Tortoise:: The Tortoise package we want to implement. * Guiling:: What Guile has to do with it. * Further:: The next steps you could take. @end menu @c ============================================================================= @node Fundamentals @chapter The Fundamentals Guile is an implementation and dialect of the Scheme programming language (Scheme is a dialect of LISP itself), intended to be used as the extension language of the GNU project. That means, that Guile is designed as a library you can include into your own project and make the interpreter run code within it; additionally, you can provide special procedures in this Guile environment that interface to the core of your application and thus allow manipulating stuff with Scheme scripts a user can write. The point of this all is to provide an easy way for you to make your application @emph{extensible} and @emph{scriptable}. For instance, if you need some sort of configuration files or even real scripting support for your application, you can use Guile instead of rolling your own ``small'' configuration or scripting language and interpreter; it already exists, so don't waste your time on yet another one but instead keep working on the new and exciting parts of your project! Having Guile as some ``universal'' scripting language (at least that's what the Guile people would like it to be, but I think it's suited to this goal) also means that a user does not have to learn different languages for each application she wants to configure or script, but instead can do so on all her favourite software with just learning Scheme. Besides, at least my personal opinion is that Scheme is very nice and fun to program in, and very well suited to small pieces of code like scripts. And the very best: The current development on Guile allows the core Guile ``platform'' to run not only Scheme code but support other languages as well on top of Guile. So you can just integrate Guile as scripting interpreter into your code, and have it also run scripts in ECMAScript, Emacs Lisp or any other language that Guile will implement in the future (like Perl, Tcl, Python or others) -- and you don't have to think a single instant about this! In concrete terms, installing Guile on your system provides basically two things for you: First, you can use the @command{guile} command-line utility as a Scheme interpreter to write programs (or as a table-top calculator if you want to). Second, use the @kbd{libguile} programming library to run applications using Guile as scripting extension; or write your own that can access the interpreter and make use of it to script your code. @c ============================================================================= @node Tortoise @chapter The Tortoise @quotation ``Why did you call him Tortoise, if he wasn't one?'' Alice asked. ``We called him Tortoise because he taught us,'' said the Mock Turtle angrily. (Lewis Carroll, Alice's Adventures in Wonderland) @end quotation As the project to demonstrate Guile, we're going to develop a very simple ``Turle'' graphics program. It will use Gnuplot for graphics output, but should be easy to adapt to any other graphics systems. It will produce graphics output by assuming that there's a tortoise sitting in the middle of the screen; this tortoise is able to perform some basic instructions given by the user. You can ask it to turn left by a certain number of degrees (or right by giving a negative number), or you can ask it to walk a certain number of steps forward. It has got a pen and you can ask it to carry it either in its paws or behind its ear, so that when it moves it will leave a mark on the ground or not. Finally, if you got yourself and the poor tortoise completely confused, you can ask it to walk away to a fresh (empty) ground, sit in the middle and face right, just as at the very start. @menu * Backend:: The core tortoise system. * First Test:: Testing the backend. @end menu @node Backend @section The Core System Let's finally start and implement the core program that will keep track of the tortoise, its movements and the graphics output. This will be implemented in C. As mentioned before, I'm going to use Gnuplot for the graphics output (at first I wanted to use the Gtk+ toolkit, but there were some problems with this approach I will come back to later). The idea is to start a Gnuplot process in the background and send it commands to draw the lines we want on the screen over a pipe. Here's the code for a program that will start up a Gnuplot process and keep connected to it via a pipe ready to get further plotting commands: @verbatim /* Simple backend for a Logo like tortoise drawer. */ #include #include #include static const int WIDTH = 10; static const int HEIGHT = 10; static FILE* start_gnuplot () { FILE* output; int pipes[2]; pid_t pid; pipe (pipes); pid = fork (); if (!pid) { dup2 (pipes[0], STDIN_FILENO); execlp ("gnuplot", NULL); return; /* Not reached. */ } output = fdopen (pipes[1], "w"); fprintf (output, "set multiplot\n"); fprintf (output, "set parametric\n"); fprintf (output, "set xrange [-%d:%d]\n", WIDTH, WIDTH); fprintf (output, "set yrange [-%d:%d]\n", HEIGHT, HEIGHT); fprintf (output, "set size ratio -1\n"); fprintf (output, "unset xtics\n"); fprintf (output, "unset ytics\n"); fflush (output); return output; } static FILE* global_output; int main (int argc, char* argv[]) { global_output = start_gnuplot (); return EXIT_SUCCESS; } @end verbatim Note that here we're not doing any error checks on the system routines; you shouldn't be doing this yourself, but it keeps this code as simple as possible. As that so far has nothing to do with what you want to read about in this tutorial, I think this should be the best way to go. What we're doing here is starting a Gnuplot process with the @var{start_gnuplot} routine and opening a pipe that can feed commands to it into @var{global_output}, so that we are later able to plot lines. Gnuplot is started with a fixed coordinate range (-10 to 10 in both x and y directions). We're going to use parametric mode so we won't get any problems drawing vertical lines, and multiplot mode in order to allow building the graphics incrementally by adding single lines each at a time. Now, this code adds a routine for plotting a line from (@var{x1}, @var{y1}) to (@var{x2}, @var{y2}): @verbatim static void draw_line (FILE* output, double x1, double y1, double x2, double y2) { fprintf (output, "plot [0:1] %f + %f * t, %f + %f * t notitle\n", x1, x2 - x1, y1, y2 - y1); fflush (output); } @end verbatim (You may want to read up on parametric plotting in Gnuplot or on parametric equations for lines if you're not sure what's going on here. Or just believe me that this will do what we want for the moment.) Finally, we can write the routines that will control the tortoise; here's some trigonometry involved, and you will need to @verb{|#include |}: @verbatim static double x, y; static double direction; static int pendown; static void tortoise_reset () { x = y = 0.0; direction = 0.0; pendown = 1; fprintf (global_output, "clear\n"); fflush (global_output); } static void tortoise_pendown () { pendown = 1; } static void tortoise_penup () { pendown = 0; } static void tortoise_turn (double degrees) { direction += M_PI / 180.0 * degrees; } static void tortoise_move (double length) { double newX, newY; newX = x + length * cos (direction); newY = y + length * sin (direction); if (pendown) draw_line (global_output, x, y, newX, newY); x = newX; y = newY; } @end verbatim That's it, just add a @verb{|tortoise_reset ();|} call to the @var{main} routine after starting Gnuplot, so that the tortoise starts at a well-defined position. @node First Test @section Testing it out Of course you want to try it now, don't you? At least I'm burning with excitement... So, we're going to give the tortoise actually some instructions, directly via C code in the @var{main} routine: @verbatim { int i; tortoise_pendown (); /* This is unnecessary, but makes it clearer. */ for (i = 1; i <= 4; ++i) { tortoise_move (3.0); tortoise_turn (90.0); } } @end verbatim As a side-note: This program leaves the Gnuplot process alive when terminating; we could send it a @command{quit} command before finishing, but later on we won't be able to do so and instead of cooking up anything more complicated, I'll just leave it like that. It basically works like that and even has the advantage that the Gnuplot window stays open until you close it, despite the fact that our tortoise-program has already finished. And if you get worried about the processes, just do a @command{killall gnuplot} afterwards... I don't know about you, but I myself like using Makefiles; so save the full code we've worked out to @file{tortoise.c} and this as @file{Makefile}: @verbatim # Basic Makefile for the tortoise package. CFLAGS = LIBS = .PHONY: clean build run build: tortoise clean: rm -f tortoise tortoise.o run: tortoise ./tortoise tortoise: tortoise.o gcc $< -o $@ $(LIBS) tortoise.o: tortoise.c gcc -c $< -o $@ $(CFLAGS) @end verbatim Of course, @var{CFLAGS} and @var{LIBS} are quite useless at the moment, but they will get some use later, so I just included them right away. Now, doing a @command{make run} should compile and run your code and open up a Gnuplot window with the resulting graphics; for me it looks like this: @image{plot1} Congratulations, you've just done your first tortoise-graphics! Still, we don't want to fix and compile the instructions directly with our C code as we just did; instead, the user should be able to interactively control the tortoise. @c ============================================================================= @node Guiling @chapter Becoming Guiled This is where Guile comes into play. Without it, we could write some additional code that reads, parses and interprets commands to the tortoise, calling the appropriate tortoise primitives as already defined. Sounds not too bad? Well, probably it isn't. But in the C code we also used a loop to draw the square -- otherwise we would have had to repeat the same two lines (movement and turn) four times. And what if we wanted to draw a polygon with, say, 1024 vertices? I hope you are convinced now that to make our tool really useful, we also needed to implement some means of looping. Hm, while we're at it: Our tortoise-package can also be used to build up a Koch's curve quite elegantly using recursion (try a quick internet search if you can't wait until I'll come back to it in more detail later) -- so want to implement some sort of procedures that can recursively call themselves? All in all, we were probably going to implement a full-fledged tortoise programming language -- but think about it: Has this anything to do with our original application and goal? I hate to spoil you all the fun (writing programming languages can be quite fun), but no, it hasn't. Luckily, we need not go through all this effort; Guile already provides a perfectly good way of making our tortoise programmable. Scheme should be quite a good language to perform all we want (loops, procedures, recursion) -- and much more. We just need to link our tortoise to the Guile-world, which will be the topic of the next sections. @menu * Init Guile:: Getting Guile into our program. * Second Test:: Run it again. * Register Functions:: Getting the tortoise into Guile. * Third Test:: Finally run it. @end menu @node Init Guile @section Adding Guile First, let's add Guile to our code; you need to @verb{|#include |} as the ``master header''. In our @var{main} routine, take out again the temporary test code we used to produce the first output, and replace it instead by these lines: @verbatim scm_with_guile (®ister_functions, NULL); scm_shell (argc, argv); @end verbatim @var{scm_with_guile} may be a bit weird at first glance; what it does is calling the provided routine (@var{register_functions} -- we'll create it in a few moments), but it also ``activates'' Guile during this call, so that other Guile library functions can be called from within @var{register_functions}. Don't worry about what exactly goes on there, you just need to remember that this indirection is necessary if you want to work with Guile. (As a side-note: There's also a @var{scm_init_guile} method that does this ``activation'' directly and without this peculiar call-back; it may seem more reasonable and easy-to-understand to you, and you can well use that one instead. However, Guile recommends using @var{scm_with_guile} for better portability where possible.) The call to @var{scm_shell} actually runs the Guile REPL (Read-Evaluate-Print Loop, that shell-like command prompt for interactive Scheme evaluation you also get when starting up @command{guile} directly) -- the idea is to do all the initialization we need for our application, and finally run the REPL, where the user can then enter her commands in Scheme code. Actually, this routine does a little more: It also processes the command-line arguments given to our tortoise-program in the way @command{guile} handles its arguments; for instance, you can then do @command{tortoise -s foobar.scm} and have your commands read from @file{foobar.scm}. That's why we need to pass it @var{argc} and @var{argv}, in case you were interested. @var{scm_shell} does not return, but rather keep on until the user closes the REPL; then our tortoise-program will also finish as a whole. Do you remember that I still owe you an explanation why using the Gtk+ toolkit for graphics would have been more complicated than Gnuplot? The reason I decided against Gtk+ is that for the Gtk+ toolkit, you do something similar: After your program's initialization, you call out to a Gtk+ main loop that will process incoming events and also never fully return control to your program -- but in this case, we can't run @emph{both} Gtk+'s main loop and the Guile REPL; at least not without writing a multi-threaded application, and that would have been again some unnecessary complication; I hope you agree with me now... But if not, just go ahead and try converting our package to Gtk+! I guess that's an interesting exercise. Finally, we still have to create @var{register_functions}: @verbatim static void* register_functions (void* data) { return NULL; } @end verbatim You're right, it's not really interesting or even useful for now, but we'll fill it in later. Notice the two @verb{|void*|}? The argument @var{data} gets passed whatever we want from @var{scm_with_guile} -- that's why there's @verb{|NULL|} as second argument in the call, but we could make it a pointer to an integer or even a large struct in case we needed to pass some data to @var{register_functions}. In turn, the return value of @var{register_functions}, which is also @verb{|NULL|} in this case but could be anything as complex as you want, is returned from @var{scm_with_guile} -- something we also don't need. @node Second Test @section Compiling with Guile Once again, we'll try to compile and run what we have so far. To do so, we have to tell the compiler where to look for @file{libguile.h} as well as the linker to include @kbd{libguile}. You can work out the appropriate flags for yourself, but the utility @command{guile-config} that comes with Guile can do it for you. So all we need to do is update the Makefile like this (and now the variables get some meaning!): @verbatim CFLAGS = `guile-config compile` LIBS = `guile-config link` @end verbatim With these adaptions, you should be able to compile and run the program again. This time, the Gnuplot window that pops up should just be empty (and stay so), but on the command-line a Guile REPL will be available just as if you had started @command{guile} yourself. You can do some Scheme programming, but so far nothing to use our little tortoise at all: @verbatim guile> (define (foobar a b) (+ a b)) guile> (foobar (* 2 3) 4) 10 guile> (map foobar '(1 2 3) '(4 5 6)) (5 7 9) guile> (tortoise-reset) Backtrace: In current input: 1: 0* (tortoise-reset) :1:1: In expression (tortoise-reset): :1:1: Unbound variable: tortoise-reset ABORT: (unbound-variable) @end verbatim That's quite nice, isn't it? Still, without control over the tortoise, it does not make sense at all; you can just use @command{guile} directly without all the effort we went through in order to program in Scheme. But we can fix this easily. @node Register Functions @section Adding the Tortoise As I've promised, we'll integrate the tortoise into the Guile environment now. We can simply tell Guile to make our tortoise-procedures available from Scheme with @var{scm_c_define_gsubr}; these need to be called from within the activated ``Guile mode'', so we add the calls to @var{register_functions}: @verbatim scm_c_define_gsubr ("tortoise-reset", 0, 0, 0, &tortoise_reset); scm_c_define_gsubr ("tortoise-penup", 0, 0, 0, &tortoise_penup); scm_c_define_gsubr ("tortoise-pendown", 0, 0, 0, &tortoise_pendown); scm_c_define_gsubr ("tortoise-turn", 1, 0, 0, &tortoise_turn); scm_c_define_gsubr ("tortoise-move", 1, 0, 0, &tortoise_move); @end verbatim The first arguments are the Scheme-names for the procedures we're going to register, the last arguments pointers to the C functions that implement them. The numbers inbetween define the number of arguments the procedures take, namely required, optional and whether there's a rest-list argument nor not -- in our case, there are neither optional arguments nor rest-lists, but @command{tortoise-turn} and @command{tortoise-move} take one required argument (the angle or distance, respectively). Unfortunatly, this is only one half of the changes needed; Guile represents all Scheme values with the @kbd{SCM} type, and thus both the return values and argument-types of the C procedures need to be @kbd{SCM}'s. In order to get the @verb{|double|} values out, we need some Guile API functions; our tortoise procedures become: @verbatim static SCM tortoise_reset () { x = y = 0.0; direction = 0.0; pendown = 1; fprintf (global_output, "clear\n"); fflush (global_output); return SCM_UNSPECIFIED; } static SCM tortoise_pendown () { SCM result = scm_from_bool (pendown); pendown = 1; return result; } static SCM tortoise_penup () { SCM result = scm_from_bool (pendown); pendown = 0; return result; } static SCM tortoise_turn (SCM degrees) { const double value = scm_to_double (degrees); direction += M_PI / 180.0 * value; return scm_from_double (direction * 180.0 / M_PI); } static SCM tortoise_move (SCM length) { const double value = scm_to_double (length); double newX, newY; newX = x + value * cos (direction); newY = y + value * sin (direction); if (pendown) draw_line (global_output, x, y, newX, newY); x = newX; y = newY; return scm_list_2 (scm_from_double (x), scm_from_double (y)); } @end verbatim You've already guessed it, @var{scm_to_double} gets the value ``out of'' a Scheme number (if it is a number at all, but we won't care about this and assume we're only fed correct arguments). You also noticed for sure that I made our procedures return some ``reasonable'' values, using some other Guile API stuff: @verb{|SCM_UNSPECIFIED|} means just that there's no return value (like @verb{|void|} in C), and if you define a procedure that has no meaningful result, you at least need to return @verb{|SCM_UNSPECIFIED|} from it to make Guile happy (and assert this fact). The @command{penup} and @command{pendown} commands return (as a Scheme boolean, created by @var{scm_from_bool}) the state of the pen before the requested change. @command{turn} and @command{move} return the new direction and coordinate (as a Scheme list with two entries), respectively -- of course, you already know what @var{scm_from_double} and @var{scm_list_2} do, right? Congratulations, now we've managed to build the whole tortoise package with Guile! And left is all the fun working with it... @node Third Test @section Having Fun with our Tortoise Recompile the program (should be easy thanks to our neat Makefile) and run it. Once again, you should get the Guile (Tortoise!) REPL, but now our procedures should really be available. Try out all of the functionality with a session like this: @verbatim guile> (tortoise-move 1) (1.0 0.0) guile> (tortoise-turn 90) 90.0 guile> (tortoise-penup) #t guile> (tortoise-move 5) (1.0 5.0) guile> (tortoise-pendown) #f guile> (tortoise-move 1) (1.0 6.0) guile> (tortoise-reset) guile> (tortoise-move (sqrt 2)) (1.4142135623731 0.0) guile> (quit) @end verbatim (I won't include the expected graphics output, just see for yourself...) I hope everything works for you, too. If not, it's the perfect time to go back to the code and try to find what's going wrong... Otherwise, let's have some fun and do real programming with our tortoise! For instance, we can automate the task of drawing polygons with a Scheme function; try out this code: @lisp (define (draw-polygon! circumference vertices) (let ((side (/ circumference vertices)) (angle (/ 360 vertices))) (let iterate ((i 1)) (if (<= i vertices) (begin (tortoise-move side) (tortoise-turn angle) (iterate (1+ i))))))) (draw-polygon! 16 4) (tortoie-penup) (tortoise-move 1) (tortoise-turn 30) (tortoise-pendown) (draw-polygon! 12 3) (tortoise-penup) (tortoise-move -2) (tortoise-turn -100) (tortoise-pendown) (draw-polygon! 10 64) @end lisp This is what I get, but try for yourself: @image{plot2} Remember that I promised you something about Koch's curve? Now we're going to construct it, using a recursive function. See for instance @uref{http://en.wikipedia.org/wiki/Koch_curve} for details about what Koch's curve is. Anyways, here comes the code; try to find out how it works, if you want: @lisp (define (koch-line length depth) (if (zero? depth) (tortoise-move length) (let ((sub-length (/ length 3)) (sub-depth (1- depth))) (for-each (lambda (angle) (koch-line sub-length sub-depth) (tortoise-turn angle)) '(60 -120 60 0))))) (define (snowflake length depth sign) (let iterate ((i 1)) (if (<= i 3) (begin (koch-line length depth) (tortoise-turn (* sign -120)) (iterate (1+ i)))))) (snowflake 8 3 1) (tortoise-turn 180) (snowflake 8 3 -1) @end lisp Are you impressed? I hope at least a little so... Unfortunatly, the Gnuplot-over-a-pipe approach is quite slow (at least on my system), so you could probably have been even more impressed if the graphics would have been there more quickly; but anyways, at least I like this very much! Regarding the Scheme code, I won't comment it further, as not to spoil all your fun thinking about it. I encourage you to do so, I like this recursive construction very much. Oh, and here's my resulting plot: @image{plot3} Looks quite interesting, doesn't it? By the way, this is also for me the first time I constructed the ``inverse'' snowflake with ``negative sign'' -- I don't know if that's done in general, but I just wanted to know the result, so here it is (the left half of the image, which got constructed by the second call). @c ============================================================================= @node Further @chapter Next Steps I hope this introduction so far gave you an idea about what Guile can do for you and how it basically works. For what I needed with my first Guile project, the stuff so far was nearly enough; however, that was of course only the tip of the iceberg, and there's @emph{a lot} of things you could still learn. For instance, there are of course a whole lot of other functions in the Guile library to work with Scheme objects; nearly any primitive that is accessible from Scheme can be used from within a C procedure, also -- there's even a routine to capture continuations! Starting up a REPL as we did is nice, but if you just want to run a user's configuration script at start-up of your application and then continue with your code, there are also routines that evaluate single Scheme commands or even run a file and return afterwards. And if you decided that one tortoise is not enough, you could introduce some sort of ``tortoise object'' that can be created and passed to the various routines so that a user can control as many tortoises as she wants -- such a user-defined Scheme object is called a @dfn{SMOB} in Guile and is of course also easy to realize. If you ever really need any of the stuff I mentioned or are just curious about what else you can do, I strongly suggest you browse the @uref{http://www.gnu.org/software/guile/manual/, Guile Reference Manual}. Surely you can find all you need (and much more) there! And if you need further help, try asking on the @uref{http://www.gnu.org/software/guile/mail/mail.html, Mailing Lists}. Finally, I hope my write-up was useful to you; in case you have any comments, suggestions, tips or just want to drop me some note whatsoever, I look forward to receiving a message. You can contact me as Daniel Kraft, @email{d@@domob.eu}. Good luck with Guile and hopefully you also enjoyed reading through this tutorial a little bit! @contents @bye --------------010600070300030708070409 Content-Type: text/plain; name="Makefile" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="Makefile" # Basic Makefile for the tortoise package. CFLAGS = `guile-config compile` LIBS = `guile-config link` .PHONY: clean build run build: tortoise clean: rm -f tortoise tortoise.o run: tortoise ./tortoise tortoise: tortoise.o gcc $< -o $@ $(LIBS) tortoise.o: tortoise.c gcc -c $< -o $@ $(CFLAGS) --------------010600070300030708070409 Content-Type: text/plain; name="tortoise.c" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="tortoise.c" /* Simple backend for a Logo like tortoise drawer. */ #include #include #include #include #include static const int WIDTH = 10; static const int HEIGHT = 10; static FILE* start_gnuplot () { FILE* output; int pipes[2]; pid_t pid; pipe (pipes); pid = fork (); if (!pid) { dup2 (pipes[0], STDIN_FILENO); execlp ("gnuplot", NULL); return; /* Not reached. */ } output = fdopen (pipes[1], "w"); fprintf (output, "set multiplot\n"); fprintf (output, "set parametric\n"); fprintf (output, "set xrange [-%d:%d]\n", WIDTH, WIDTH); fprintf (output, "set yrange [-%d:%d]\n", HEIGHT, HEIGHT); fprintf (output, "set size ratio -1\n"); fprintf (output, "unset xtics\n"); fprintf (output, "unset ytics\n"); fflush (output); return output; } static void draw_line (FILE* output, double x1, double y1, double x2, double y2) { fprintf (output, "plot [0:1] %f + %f * t, %f + %f * t notitle\n", x1, x2 - x1, y1, y2 - y1); fflush (output); } static double x, y; static double direction; static int pendown; static FILE* global_output; static SCM tortoise_reset () { x = y = 0.0; direction = 0.0; pendown = 1; fprintf (global_output, "clear\n"); fflush (global_output); return SCM_UNSPECIFIED; } static SCM tortoise_pendown () { SCM result = scm_from_bool (pendown); pendown = 1; return result; } static SCM tortoise_penup () { SCM result = scm_from_bool (pendown); pendown = 0; return result; } static SCM tortoise_turn (SCM degrees) { const double value = scm_to_double (degrees); direction += M_PI / 180.0 * value; return scm_from_double (direction * 180.0 / M_PI); } static SCM tortoise_move (SCM length) { const double value = scm_to_double (length); double newX, newY; newX = x + value * cos (direction); newY = y + value * sin (direction); if (pendown) draw_line (global_output, x, y, newX, newY); x = newX; y = newY; return scm_list_2 (scm_from_double (x), scm_from_double (y)); } static void* register_functions (void* data) { scm_c_define_gsubr ("tortoise-reset", 0, 0, 0, &tortoise_reset); scm_c_define_gsubr ("tortoise-penup", 0, 0, 0, &tortoise_penup); scm_c_define_gsubr ("tortoise-pendown", 0, 0, 0, &tortoise_pendown); scm_c_define_gsubr ("tortoise-turn", 1, 0, 0, &tortoise_turn); scm_c_define_gsubr ("tortoise-move", 1, 0, 0, &tortoise_move); return NULL; } int main (int argc, char* argv[]) { global_output = start_gnuplot (); tortoise_reset (); scm_with_guile (®ister_functions, NULL); scm_shell (argc, argv); return EXIT_SUCCESS; } --------------010600070300030708070409--