Printing text in the console is essential to be able to debug your code. There are several ways to do that.

The display function prints any object (be it a string or not). Use it several times to print several objects. display does not insert any newlines automatically; you need to add a newline at the end of the string (if you are displaying a string), or to add a call (display "\n"), which can be shortened as (newline). For example, this code:

(define surname "Salima")
(display "Hello ")
(display surname)
(display "!\n")

can also be written

(define surname "Salima")
(display "Hello ")
(display surname)
(display "!")

Both of the examples above were somewhat tedious. It is more convenient to use the format procedure. To begin, we are going to use #t as its first argument (read on to understand what this object is). The second argument is a string, which can contain special sequences. There must be the same number of remaining arguments as special sequences. They are formatted in a certain way depending on which special sequence is used, and inserted in the string. The formatted string is then displayed on the console. One of the commonly used escape sequences is ~a, which prints objects exactly like display would.

(define surname "Salima")
(format #t "Hello ~a!\n" surname)
 Hello Salima!

With #t, format returns an unimportant value. On the other hand, if #f is used, format returns the formatted string, without displaying it:

(define surname "Salima")
(format #f "Hello ~a!" surname)
 "Hello Salima!"

As an example, LilyPond extensively uses format with #f to build its PostScript output. The following code excerpt is taken from framework-ps.scm.

(format #f "%%BeginDocument: ~a
          (cached-file-contents file-name))

There is another procedure, which is defined by LilyPond, called ly:message. It works much like format. Its only purpose is to display the messages, so it does not take the first argument #t or #f; it is as if #t were used. Its advantage is that it prints the message in the standard error stream, not in the standard output stream, which prevents it from being intermingled with the rest of logging messages in the Frescobaldi interface (or another interface). (Actually, it would be possible to replace #t with (current-error-port) in format to get the same effect.) Moreover, ly:message automatically prepends a newline.

(define file "emmentaler-20.otf")
(ly:message "Reading ~a..." file)
 Reading emmentaler-20.otf...

Another special sequence is ~s. It formats values like the sandbox would do. For example, it prints quotes around strings. ~s is more suitable for debugging than ~a.

(define file "emmentaler-20.otf")
(ly:message "Reading ~s..." file)
 Reading "emmentaler-20.otf"...