[GoLUG] Yet again ... returning to the strange one: Guile 3.0 aka Scheme

Barry Fishman barry at ecubist.org
Tue Aug 27 13:30:56 EDT 2024


On 2024-08-27 02:55:24 GMT, David Billsbrough wrote:
> ...
> Both these languages can easily run from the command line and
> 'compile' quickly.  I have not really figured
> out the 'debugger' of Guile and just do a lot of print statements.
> Have not really master concatenation of
> strings in scheme!  Getting a little better and integer conversion with "Tcl."
The Guile documentation is very terse, which makes it difficult to
learn.  I started learning Guile after spending some time programming in
Common Lisp, which has very good documentation, so I had an easier time
picking up a different Lisp like language.

I also tend to use print statements in Guile rather than the debugger.

I tend to write a DEBUG function in the beginning of the file,
appropriate to the kinds of things I want to print and then use that to
print the debug output  It lets me easily search for "DEBUG" to find all
the debug statements and remove them when I am done.

For example:

(define *debug* #t)
(define (DEBUG . lst)
  (when *debug*
    (display "DEBUG:")
    (for-each (lambda (arg)
                (display " ")
                (display arg))
              lst)
    (newline)))

So I can print things more simply like:

 (DEBUG "After adding:" "X:" x "Y:" y "Is:" (+ x y))

And disable them by changing the *debug* value to #f.  This
is easier than dealing with any parenthesis issues when I want
to enable or disable the debug messages.

I start my Guile scripts with something like:

#! /bin/sh
## Guile -*- mode: scheme; coding: utf-8 -*-
## Time-stamp: <2024-06-30 10:19:32 barry>
exec ${GUILE:-guile} -e main -s $0 ${1+"$@"}
!#

This makes the script execute starting with an function

 (define (main args)
   ...)

and use the proper Vim/Emacs editor setup. I can get both Vim and Emacs
to recognize it as a guile scheme program, and update the timestamp when
I save the file.

[It also uses the environment variable GUILE, when defined, to pick
the guile program. I needed it on systems when guiles2 and guile3
both existed, and the default guile was guile2.  I have lots of
guile scripts and hand editing them for each system would be a pain.]

I can run the file directly as a script, or just load the program
by doing, (if the script is called my-script):

$ guile -l my-script

and then from the REPL, invoke the scheme code interactively (with tab
completion), or just run the program with:

scheme@(guile-user)> (main '("my-script" "arg1" "arg2"))

You can also use the results of a previous expression, so:

scheme$(guile-user)> (+ 3 2)
$1 = 5
scheme$(guile-user)> (+ $1 5)
$2 = 10

In this REPL mode, the help system and debugger are available
with ","  prefixed commands.  To get a list of the commands
available:

scheme@(guile-user)> ,help

or just:

scheme@(guile-user)> ,h

Get information on a possible command with ",a" or:

scheme(guile-user)> ,apropos concat
(guile): string-concatenate	#<procedure string-concatenate (_)>
(guile): string-concatenate-reverse/shared	#<procedure string-concatenate-reverse/shared (_ #:optional _ _)>
(guile): string-concatenate-reverse	#<procedure string-concatenate-reverse (_ #:optional _ _)>
(guile): string-concatenate/shared	#<procedure string-concatenate/shared (_)>

And then with ",d" or:

scheme@(guile-user)> ,describe string-concatenate
- Scheme Procedure: string-concatenate ls
     Append the elements of LS (which must be strings) together into a
     single string.  Guaranteed to return a freshly allocated string.

May be not quite what you may want but

scheme@(guile-user)> ,a append
(guile): symbol-append	#<procedure symbol-append args>
(guile): string-append	#<procedure string-append _>
(guile): string-append/shared	#<procedure string-append/shared _>
(guile): append!	#<procedure append! _>
(guile): append	#<procedure append _>

scheme@(guile-user)> ,d string-append
- Scheme Procedure: string-append .  args
     Return a newly allocated string whose characters form the
     concatenation of the given strings, ARGS.

Note that "string-append . args" is Guile's way of showing
"(string-append arg1 arg2 ...)" with 0 or more args.

As far as debugging the command help works like:

scheme@(guile-user)> ,help debug
...
,break PROCEDURE        [,br ,bp] - Break on calls to PROCEDURE.
,break-at-source FILE LINE
                   [,break-at ,bs] - Break when control reaches the given source location.
...

scheme@(guile-user)> ,help -c bs
Break when control reaches the given source location.

Starts a recursive prompt when control reaches line LINE of file FILE.
Note that the given source location must be inside a procedure.


Also note that if you do a lot of string concatenation in a program and
its a pain to type things like (string-append "foo" "bar") all the time,
you can do something like:

(define ++ string-append)

And use (++ "foo" "bar") and (++ "foo" "bar" "whatever" "else") instead.

Things like this are done all the time in normal scheme code.

        ------------------------------------------------

But if you like to live on the *edge*, (or as I do) have been programming
in Guile for 20 years, you can do things I'll preview in the rest of
this message.

(import (oop goops))
(define-method (+ (s <string>) . lst)
  (string-concatenate (cons s lst)))

And then:

scheme@(guile-user)> (+ "3" "5")
$1 = "35"
scheme@(guile-user)> (+ 3 5)
$2 = 8
scheme@(guile-user)> (+ 3 5 9)
$3 = 17
scheme@(guile-user)> (+ "3" "5" "9")
$4 = "359"

But I *really* don't recommend it.

== Deeper in the rabbit hole ==

For example to allow primitive infix code in guile you can turn on
[ from Scheme srfi-105 https://srfi.schemers.org/srfi-105/ ]
curly-infix mode:

#!curly-infix
{"3" + "5" + "9"}
$5 = "359"
{3 + string-length("foo")}
$6 = 6

And your new overridden "+" function can be used as in infix function,
even though the infix code handling and your new + method are done
without any knowledge of each other.  Curly-infix is really basic
so it doesn't deal with operator precedence, so
you need to do things like:

{{3 * 2} - 5}

-- 
Barry



More information about the GoLUG mailing list