unofficial mirror of guile-devel@gnu.org 
 help / color / mirror / Atom feed
* Updated Guile Tutorial
@ 2009-08-06 18:34 Daniel Kraft
  2009-08-12 22:27 ` Andy Wingo
  0 siblings, 1 reply; 14+ messages in thread
From: Daniel Kraft @ 2009-08-06 18:34 UTC (permalink / raw)
  To: guile-devel

[-- Attachment #1: Type: text/plain, Size: 1287 bytes --]

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

[-- Attachment #2: plot1.png --]
[-- Type: image/png, Size: 1320 bytes --]

[-- Attachment #3: plot2.png --]
[-- Type: image/png, Size: 4237 bytes --]

[-- Attachment #4: plot3.png --]
[-- Type: image/png, Size: 12805 bytes --]

[-- Attachment #5: tutorial.html --]
[-- Type: text/html, Size: 48607 bytes --]

[-- Attachment #6: tutorial.texi --]
[-- Type: text/plain, Size: 27828 bytes --]

\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 <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;
}
@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 <math.h>|}:

@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 <libguile.h>|}
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 (&register_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)

<unnamed port>:1:1: In expression (tortoise-reset):
<unnamed port>: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


[-- Attachment #7: Makefile --]
[-- Type: text/plain, Size: 302 bytes --]

# 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)

[-- Attachment #8: tortoise.c --]
[-- Type: text/plain, Size: 2667 bytes --]

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

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

#include <libguile.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 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 (&register_functions, NULL);
  scm_shell (argc, argv);

  return EXIT_SUCCESS;
}

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Updated Guile Tutorial
  2009-08-06 18:34 Updated Guile Tutorial Daniel Kraft
@ 2009-08-12 22:27 ` Andy Wingo
  2009-08-13  7:43   ` Daniel Kraft
                     ` (2 more replies)
  0 siblings, 3 replies; 14+ messages in thread
From: Andy Wingo @ 2009-08-12 22:27 UTC (permalink / raw)
  To: Daniel Kraft; +Cc: guile-devel

On Thu 06 Aug 2009 20:34, Daniel Kraft <d@domob.eu> writes:

> 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.

This is great work. Thanks for bringing our tutorial up to date! I just
looked over the existing tutorial, and wow, anything that mentions Lotus
1-2-3, and fvwm...

A few comments, IMO of course. Neil probably has a better perspective.

 1) It would be better to have a more neutral narrator -- not a
    first-person narrator. If you feel like you need to speak from the
    first person, use "we". OTOH your style is infectious :), so perhaps
    it would work as "Guile Tutorial, by Daniel Kraft" :)

 2) Don't mention the history of the tutorial. Just have it be a current
    document.

 3) In general, use short sentences. Let your words breathe.

 4) If you're forking to run gnuplot, why not do so from Scheme? Of
    course if you did that it would obviate the whole "extending C"
    story, but still, if given this particular problem, that's what I'd
    do.

 5) Running a main loop (as gtk+ does) and a REPL is indeed an
    interesting problem. See event-repl.scm or graphical-repl.scm in
    guile-gnome for a couple of takes.

 6) I wish we had a better Scheme->C story; our C->Scheme story is fine,
    but a better FFI would be nice.

Anyway, IMO, FWIW, etc. If you don't reply, I'll probably just commit
your tutorial more-or-less as-is to the repo :)

A
-- 
http://wingolog.org/




^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Updated Guile Tutorial
  2009-08-12 22:27 ` Andy Wingo
@ 2009-08-13  7:43   ` Daniel Kraft
  2009-08-24 15:39   ` Daniel Kraft
  2009-09-20 16:42   ` Neil Jerram
  2 siblings, 0 replies; 14+ messages in thread
From: Daniel Kraft @ 2009-08-13  7:43 UTC (permalink / raw)
  To: Andy Wingo; +Cc: guile-devel

Hi Andy,

thanks for your comments and checking over my revised tutorial!

Andy Wingo wrote:
> A few comments, IMO of course. Neil probably has a better perspective.

I agree with you in general on those, and will try what I can improve on 
them; so please wait with a commit in any case ;)  Should I think that 
the current version is best of all my trials, I'll also let you know...

>  1) It would be better to have a more neutral narrator -- not a
>     first-person narrator. If you feel like you need to speak from the
>     first person, use "we". OTOH your style is infectious :), so perhaps
>     it would work as "Guile Tutorial, by Daniel Kraft" :)

That's something I usually also try to achieve in writings "like that" 
-- however, I liked the original's style and tried to get my own version 
in the same spirit.  Here, I'm not sure if I can get rid of first person 
entirely; and I think I tried to use "we" wherever possible, but for 
stuff like "I wanted to use Gtk+ but resided finally to Gnuplot 
because..." I'm not sure how to do this; overall, it's really meant from 
the author's perspective and not something like "we're going to do that 
now".

I'll still try to work over the text when I find time and maybe I can 
reformulate it -- concrete suggestions are welcome, if you stumble upon 
certain passages, of course.

>  2) Don't mention the history of the tutorial. Just have it be a current
>     document.

I wanted to give credits to the original author, but you're right that I 
should probably move this to some concluding section.  As you make me 
think about that, I also need to add a GNU FDL note somewhere.

>  3) In general, use short sentences. Let your words breathe.

Ok, I'll see what can be done there; I just fear that this is a 
remainder of German being my native language, so I'm usually not content 
with short sentences...

>  4) If you're forking to run gnuplot, why not do so from Scheme? Of
>     course if you did that it would obviate the whole "extending C"
>     story, but still, if given this particular problem, that's what I'd
>     do.

I've never tried this actually myself, but I think it would not be too 
hard to implement all of this in Scheme alone; but as you mentioned, I 
just needed something to write in C ;)

But if you've got a suggestion as what I could reasonable still change 
(maybe some final remarks that this example would also be possible in 
Scheme) I'll consider it.

>  5) Running a main loop (as gtk+ does) and a REPL is indeed an
>     interesting problem. See event-repl.scm or graphical-repl.scm in
>     guile-gnome for a couple of takes.

I imagine the "correct" solution would be to start the REPL in a 
seperate thread and do drawing by updating some shared data structure 
that is read and rendered from the Gtk+ loop's exposed-callbacks; or 
something alike.

This shouldn't be too hard if we wanted to implement a clean program 
anyways, but for means of the tutorial I think the current version is 
better.

>  6) I wish we had a better Scheme->C story; our C->Scheme story is fine,
>     but a better FFI would be nice.

I'm not sure about that...  For all I did so far, the Scheme->C stuff I 
regard also as quite good.  The only thing is that you need to write 
wrappers for each function; so maybe we could try to get a FFI where you 
can just define the interface of a C function and Guile does the SCM 
boxing/unboxing accordingly on calls.  Are there already plans (or at 
least the concrete desire) to do stuff like this?  I think at least for 
some very basic functionality it should not be too hard to do?

Cheers,
Daniel

-- 
Done:  Arc-Bar-Cav-Ran-Rog-Sam-Tou-Val-Wiz
To go: Hea-Kni-Mon-Pri




^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Updated Guile Tutorial
  2009-08-12 22:27 ` Andy Wingo
  2009-08-13  7:43   ` Daniel Kraft
@ 2009-08-24 15:39   ` Daniel Kraft
  2009-09-20 16:35     ` Neil Jerram
  2009-09-20 16:42   ` Neil Jerram
  2 siblings, 1 reply; 14+ messages in thread
From: Daniel Kraft @ 2009-08-24 15:39 UTC (permalink / raw)
  To: Andy Wingo; +Cc: guile-devel

[-- Attachment #1: Type: text/plain, Size: 817 bytes --]

Hi Andy and all,

here's the promised revised version of my Guile tutorial; I did not 
change much, but at least some bits.  I moved the "historic details" and 
credits to the original tutorial to the very end and abbreviated them; 
and additionally I worked through the text and made some (in my opinion) 
improvements and clarifications -- some sentences are shorter now where 
I saw that fit, but honestly not many.

I'd like to put that under GNU FDL as license, but have no experience 
what I really need to do in order to have this correct?  It would be 
cool if you could put this somewhere accessible, or even add it to the 
"core" Guile documentation (putting it under FSF copyright).

Comments still welcome of course ;)

Yours,
Daniel

-- 
Done:  Arc-Bar-Cav-Ran-Rog-Sam-Tou-Val-Wiz
To go: Hea-Kni-Mon-Pri

[-- Attachment #2: plot1.png --]
[-- Type: image/png, Size: 1320 bytes --]

[-- Attachment #3: plot2.png --]
[-- Type: image/png, Size: 4237 bytes --]

[-- Attachment #4: plot3.png --]
[-- Type: image/png, Size: 12805 bytes --]

[-- Attachment #5: tutorial.html --]
[-- Type: text/html, Size: 47943 bytes --]

[-- Attachment #6: tutorial.texi --]
[-- Type: text/plain, Size: 27168 bytes --]

\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.

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).  It is 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.  This way, Scheme scrips written by a user can
manipulate stuff ``within'' your application.

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.  Instead she 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
``Tortoise'' 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 intstruct 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 <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;
}
@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 <math.h>|}:

@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 this way 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 <libguile.h>|}
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 (&register_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).  Additionally, 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.
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)

<unnamed port>:1:1: In expression (tortoise-reset):
<unnamed port>: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 if you want 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).  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.  This would allow a user to control as many tortoises in parallel 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}.

I want to thank David Drysdale for his own ``Tutorial Introduction to Guile'',
upon which this document is largly based (in fact, mostly a rewrite of with
some updates and -- as I see it, of course -- improvements).

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


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Updated Guile Tutorial
  2009-08-24 15:39   ` Daniel Kraft
@ 2009-09-20 16:35     ` Neil Jerram
  2009-09-20 20:31       ` Daniel Kraft
  2010-08-19  5:41       ` Andy Wingo
  0 siblings, 2 replies; 14+ messages in thread
From: Neil Jerram @ 2009-09-20 16:35 UTC (permalink / raw)
  To: Daniel Kraft; +Cc: Andy Wingo, guile-devel

Daniel Kraft <d@domob.eu> writes:

> Hi Andy and all,
>
> here's the promised revised version of my Guile tutorial;

Hi Daniel,

I've now added this to the Guile web pages, and linked to it from
http://www.gnu.org/software/guile/docs/docs.html.  Sorry for taking so
long about it.  Please let me know if you have any feedback on how I've
done this.

> I'd like to put that under GNU FDL as license, but have no experience
> what I really need to do in order to have this correct?

The ADDENDUM at the end of http://www.gnu.org/copyleft/fdl.html explains
what you need to do.  If you send me (or the list) an update to the
.texi and .html, I'll publish the new versions to the web site.

Regards, and thanks again for doing this!

      Neil




^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Updated Guile Tutorial
  2009-08-12 22:27 ` Andy Wingo
  2009-08-13  7:43   ` Daniel Kraft
  2009-08-24 15:39   ` Daniel Kraft
@ 2009-09-20 16:42   ` Neil Jerram
  2009-09-20 17:17     ` Chris Bryant
  2009-09-20 17:18     ` Chris Bryant
  2 siblings, 2 replies; 14+ messages in thread
From: Neil Jerram @ 2009-09-20 16:42 UTC (permalink / raw)
  To: Andy Wingo; +Cc: Daniel Kraft, guile-devel

Andy Wingo <wingo@pobox.com> writes:

>  4) If you're forking to run gnuplot, why not do so from Scheme?

Coincidentally, I recently wrote this:

(define (gnuplot file-name plot-command)
  (let ((pipe (open-output-pipe "gnuplot -"))) 
    (format pipe
	    "\
set terminal png
set output '~a'
~a
quit
"
	    file-name
	    plot-command)
    (close-pipe pipe))
  (system (string-append "display " file-name)))

Example usage:

(gnuplot "table1.png"
  "plot 'table1.txt' using 1:6 with lines, 4*x/log(2*x), 4*x/log(x)")

Daniel, if you feel like including this in the tutorial as an
alternative to the C code, please do so.

> Anyway, IMO, FWIW, etc. If you don't reply, I'll probably just commit
> your tutorial more-or-less as-is to the repo :)

Although the tutorial is now on the web, I still haven't done anything
as regards committing it to Git.  That's not because I think we
shouldn't; it just that I haven't pondered how best to do it yet.

    Neil




^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Updated Guile Tutorial
  2009-09-20 16:42   ` Neil Jerram
@ 2009-09-20 17:17     ` Chris Bryant
  2009-09-20 21:13       ` Neil Jerram
  2009-09-20 17:18     ` Chris Bryant
  1 sibling, 1 reply; 14+ messages in thread
From: Chris Bryant @ 2009-09-20 17:17 UTC (permalink / raw)
  To: Neil Jerram; +Cc: Andy Wingo, Daniel Kraft, guile-devel

On Sun, 2009-09-20 at 17:42 +0100, Neil Jerram wrote:

> Although the tutorial is now on the web, I still haven't done anything
> as regards committing it to Git.  That's not because I think we
> shouldn't; it just that I haven't pondered how best to do it yet.

Neil, looks great!  Could you possibly formally create a Texinfo
document for the Guile site?  I've wanted something along the lines of
this for a while, looking to the Emacs lisp tutorial as a model.  Very
useful.


-- 
Chris Bryant,
GNU/Linux Engineer,
chrisbryant at ucla dot edu
GNU Users Group, Los Angeles
http://www.nongnu.org/gug-la/





^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Updated Guile Tutorial
  2009-09-20 16:42   ` Neil Jerram
  2009-09-20 17:17     ` Chris Bryant
@ 2009-09-20 17:18     ` Chris Bryant
  1 sibling, 0 replies; 14+ messages in thread
From: Chris Bryant @ 2009-09-20 17:18 UTC (permalink / raw)
  To: Neil Jerram; +Cc: Andy Wingo, Daniel Kraft, guile-devel

On Sun, 2009-09-20 at 17:42 +0100, Neil Jerram wrote:
> Although the tutorial is now on the web, I still haven't done anything
> as regards committing it to Git.  That's not because I think we
> shouldn't; it just that I haven't pondered how best to do it yet.

Ah, sorry, I meant to also say "Daniel, excellent work!" :)

Cheers.

- CB





^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Updated Guile Tutorial
  2009-09-20 16:35     ` Neil Jerram
@ 2009-09-20 20:31       ` Daniel Kraft
  2010-08-19  5:41       ` Andy Wingo
  1 sibling, 0 replies; 14+ messages in thread
From: Daniel Kraft @ 2009-09-20 20:31 UTC (permalink / raw)
  To: Neil Jerram; +Cc: Andy Wingo, guile-devel

Neil Jerram wrote:
> Daniel Kraft <d@domob.eu> writes:
> 
>> Hi Andy and all,
>>
>> here's the promised revised version of my Guile tutorial;
> 
> Hi Daniel,
> 
> I've now added this to the Guile web pages, and linked to it from
> http://www.gnu.org/software/guile/docs/docs.html.  Sorry for taking so
> long about it.  Please let me know if you have any feedback on how I've
> done this.

Thanks Neil!  I think that looks great as it is!

>> I'd like to put that under GNU FDL as license, but have no experience
>> what I really need to do in order to have this correct?
> 
> The ADDENDUM at the end of http://www.gnu.org/copyleft/fdl.html explains
> what you need to do.  If you send me (or the list) an update to the
> .texi and .html, I'll publish the new versions to the web site.

I'll look into that and re-send an updated version when I've found time 
to do so.

Thanks again!  Cheers,
Daniel

-- 
Done:  Arc-Bar-Cav-Ran-Rog-Sam-Tou-Val-Wiz
To go: Hea-Kni-Mon-Pri




^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Updated Guile Tutorial
  2009-09-20 17:17     ` Chris Bryant
@ 2009-09-20 21:13       ` Neil Jerram
  0 siblings, 0 replies; 14+ messages in thread
From: Neil Jerram @ 2009-09-20 21:13 UTC (permalink / raw)
  To: Chris Bryant; +Cc: Andy Wingo, Daniel Kraft, guile-devel

Chris Bryant <chrisbryant@ucla.edu> writes:

> On Sun, 2009-09-20 at 17:42 +0100, Neil Jerram wrote:
>
>> Although the tutorial is now on the web, I still haven't done anything
>> as regards committing it to Git.  That's not because I think we
>> shouldn't; it just that I haven't pondered how best to do it yet.
>
> Neil, looks great!  Could you possibly formally create a Texinfo
> document for the Guile site?

The Texinfo source is secretly already there; if you just
s/.html/.texi/, you can get it.  But I've now added an explicit link
from http://www.gnu.org/software/guile/docs/docs.html too.

Regards,
        Neil




^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Updated Guile Tutorial
  2009-09-20 16:35     ` Neil Jerram
  2009-09-20 20:31       ` Daniel Kraft
@ 2010-08-19  5:41       ` Andy Wingo
  2010-08-21 14:38         ` Daniel Kraft
  1 sibling, 1 reply; 14+ messages in thread
From: Andy Wingo @ 2010-08-19  5:41 UTC (permalink / raw)
  To: Neil Jerram; +Cc: Daniel Kraft, guile-devel

Hi,

Looking over some old mails...

On Sun 20 Sep 2009 09:35, Neil Jerram <neil@ossau.uklinux.net> writes:

> Daniel Kraft <d@domob.eu> writes:
>
>> here's the promised revised version of my Guile tutorial;
>
> I've now added this to the Guile web pages, and linked to it from
> http://www.gnu.org/software/guile/docs/docs.html.  Sorry for taking so
> long about it.  Please let me know if you have any feedback on how I've
> done this.

This is a good step, but we should have some more finality here. They
are of similar length; we should replace the old tutorial with the
new. And should the tutorial go in Guile's source distro? What about
integrated with the manual? Also at this point, it should mention the
dynamic FFI.

Thoughts appreciated, otherwise I'll make random decisions sometime
soon.

Andy
-- 
http://wingolog.org/



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Updated Guile Tutorial
  2010-08-19  5:41       ` Andy Wingo
@ 2010-08-21 14:38         ` Daniel Kraft
  2010-08-28 18:46           ` Andy Wingo
  0 siblings, 1 reply; 14+ messages in thread
From: Daniel Kraft @ 2010-08-21 14:38 UTC (permalink / raw)
  To: Andy Wingo; +Cc: guile-devel, Neil Jerram

Hi Andy,

Andy Wingo wrote:
>> Daniel Kraft <d@domob.eu> writes:
>>
>>> here's the promised revised version of my Guile tutorial;
>> I've now added this to the Guile web pages, and linked to it from
>> http://www.gnu.org/software/guile/docs/docs.html.  Sorry for taking so
>> long about it.  Please let me know if you have any feedback on how I've
>> done this.
> 
> This is a good step, but we should have some more finality here. They
> are of similar length; we should replace the old tutorial with the
> new. And should the tutorial go in Guile's source distro? What about
> integrated with the manual? Also at this point, it should mention the
> dynamic FFI.

from my point of view, I'd be glad if you replaced the old tutorial with 
my version (and included it into the source distro / manual -- feel free 
to do the copyright assignment and licensing as required for that).

What's the dynamic FFI?  I notice that I unfortunately lost contact to 
Guile some time ago (over the last year at university that was very 
work-intensive).

Yours,
Daniel;

-- 
http://www.pro-vegan.info/
--
Done:  Arc-Bar-Cav-Kni-Ran-Rog-Sam-Tou-Val-Wiz
To go: Hea-Mon-Pri



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Updated Guile Tutorial
  2010-08-21 14:38         ` Daniel Kraft
@ 2010-08-28 18:46           ` Andy Wingo
  0 siblings, 0 replies; 14+ messages in thread
From: Andy Wingo @ 2010-08-28 18:46 UTC (permalink / raw)
  To: Daniel Kraft; +Cc: guile-devel, Neil Jerram

Heya Daniel,

On Sat 21 Aug 2010 07:38, Daniel Kraft <d@domob.eu> writes:

> from my point of view, I'd be glad if you replaced the old tutorial with
> my version

I have done so on the web site, thanks.

> (and included it into the source distro / manual -- feel free
> to do the copyright assignment and licensing as required for that).

I'm happy to do that, but it would be some work -- both documents have
fine tone, but they are not the same tone ;)

Also because there's no gnuplot library, it's hard to cover the spectrum
of "extending applications in Guile".

On the other hand, there is GNU plotutils, which does have a library:

  http://www.gnu.org/software/plotutils/

But on the other other hand, it seems quite bitrotten...

> What's the dynamic FFI?  I notice that I unfortunately lost contact to
> Guile some time ago (over the last year at university that was very
> work-intensive).

See
http://www.gnu.org/software/guile/docs/master/guile.html/Dynamic-FFI.html#Dynamic-FFI.

I just updated the manual snapshot on the web site, by the way. Took a
while, as I have completely forgotten how to use CVS :P

Andy
-- 
http://wingolog.org/



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: Updated Guile Tutorial
@ 2010-09-07 13:17 Daniel Kraft
  0 siblings, 0 replies; 14+ messages in thread
From: Daniel Kraft @ 2010-09-07 13:17 UTC (permalink / raw)
  To: Andy Wingo; +Cc: guile-devel, Neil Jerram

I forgot to CC, so here again.

-------- Original Message --------
Subject: Re: Updated Guile Tutorial
Date: Tue, 07 Sep 2010 15:15:34 +0200
From: Daniel Kraft <d@domob.eu>
To: Andy Wingo <wingo@pobox.com>
References: <4A7B223E.6050501@domob.eu> <m3ljlollb7.fsf@pobox.com> 
<4A92B446.2090902@domob.eu> <87tyyxsheh.fsf@ossau.uklinux.net> 
<m3tymrtazy.fsf@unquote.localdomain> <4C6FE4E8.6030201@domob.eu> 
<m3pqx2378m.fsf@unquote.localdomain>

Andy Wingo wrote:
>> from my point of view, I'd be glad if you replaced the old tutorial with
>> my version
> 
> I have done so on the web site, thanks.

Cool!

> 
>> (and included it into the source distro / manual -- feel free
>> to do the copyright assignment and licensing as required for that).
> 
> I'm happy to do that, but it would be some work -- both documents have
> fine tone, but they are not the same tone ;)

Yes, maybe it's best to not introduce the tutorial as an "integral part"
of the manual -- but rather as a seperate item, which may be referred to
or linked to in the manual.  what do you think?

> Also because there's no gnuplot library, it's hard to cover the spectrum
> of "extending applications in Guile".
> 
> On the other hand, there is GNU plotutils, which does have a library:
> 
>   http://www.gnu.org/software/plotutils/
> 
> But on the other other hand, it seems quite bitrotten...

I also have this impression, unfortunately.  But if you see a "good" way
to do the visualization instead of forking gnuplot, I'm happy to adapt
the tutorial.

>> What's the dynamic FFI?  I notice that I unfortunately lost contact to
>> Guile some time ago (over the last year at university that was very
>> work-intensive).
> 
> See
> http://www.gnu.org/software/guile/docs/master/guile.html/Dynamic-FFI.html#Dynamic-FFI.

Well, *that* looks really cool!  I have to give it a try soon :D  Do you
have a suggestion for how to integrate this with the manual?  It seems
to me that with such a small project it does not make sense to do both
registering procedures from C and using the FFI.  But maybe we could
just call some libc function at one place?  Although I have no idea so far.

Yours,
Daniel

-- 
http://www.pro-vegan.info/
--
Done:  Arc-Bar-Cav-Kni-Ran-Rog-Sam-Tou-Val-Wiz
To go: Hea-Mon-Pri


-- 
http://www.pro-vegan.info/
--
Done:  Arc-Bar-Cav-Kni-Ran-Rog-Sam-Tou-Val-Wiz
To go: Hea-Mon-Pri



^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2010-09-07 13:17 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-08-06 18:34 Updated Guile Tutorial Daniel Kraft
2009-08-12 22:27 ` Andy Wingo
2009-08-13  7:43   ` Daniel Kraft
2009-08-24 15:39   ` Daniel Kraft
2009-09-20 16:35     ` Neil Jerram
2009-09-20 20:31       ` Daniel Kraft
2010-08-19  5:41       ` Andy Wingo
2010-08-21 14:38         ` Daniel Kraft
2010-08-28 18:46           ` Andy Wingo
2009-09-20 16:42   ` Neil Jerram
2009-09-20 17:17     ` Chris Bryant
2009-09-20 21:13       ` Neil Jerram
2009-09-20 17:18     ` Chris Bryant
  -- strict thread matches above, loose matches on Subject: below --
2010-09-07 13:17 Daniel Kraft

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).