Scheme language introduction

A first stab at all the code you'll need for 220a

Scheme programs don't need to be compiled to run. You can use them like you would a calculator. For example, emulate this dialog in a terminal

[cc@cmn36 zap]$ guile
guile> (+ 2 1234567)
1234569
guile> (quit)
[cc@cmn36 zap]$

There are a few parts to this simple example:

  1. guile is one of many scheme interpreters, you can launch it in a terminal to run in an interactive mode, quitting when it evaluates the expression (quit)

  2. expressions are bounded by parentheses and the first token specifies the procedure to execute, like (+ <args...>)

  3. the number of arguments depends on the nature of the procedure, some take none... like quit, ...some take an optional number... like +, ...and some require a fixed set of arguments

  4. the interpreter runs forever in a read-eval-print loop until something is evaluated that causes it to exit

By itself, guile is a thin, barebones implementation of the scheme language. It can be enhanced with modules and code packages like Common Music (CM) which adds smarts to the execution context. In this example, guile loads a file that pulls in all of cm and then I ask what's the midi keynum equivalent of 440.0 Hz.

guile> (load "/user/c/cc/220a/system/snd-cm/cm-2.6.0/src/cm.scm")
; Loading: /home/cc/220a/system/snd-cm/cm-2.6.0/src/guile.scm
; Loading: /home/cc/220a/system/snd-cm/cm-2.6.0/src/goops.scm
; Loading: /home/cc/220a/system/snd-cm/cm-2.6.0/src/level1.scm
; Loading: /home/cc/220a/system/snd-cm/cm-2.6.0/src/loop.scm
; Loading: /home/cc/220a/system/snd-cm/cm-2.6.0/src/utils.scm
; Loading: /home/cc/220a/system/snd-cm/cm-2.6.0/src/mop.scm
; Loading: /home/cc/220a/system/snd-cm/cm-2.6.0/src/objects.scm
; Loading: /home/cc/220a/system/snd-cm/cm-2.6.0/src/io.scm
; Loading: /home/cc/220a/system/snd-cm/cm-2.6.0/src/scheduler.scm
; Loading: /home/cc/220a/system/snd-cm/cm-2.6.0/src/sco.scm
; Loading: /home/cc/220a/system/snd-cm/cm-2.6.0/src/clm.scm
; Loading: /home/cc/220a/system/snd-cm/cm-2.6.0/src/clm2.scm
; Loading: /home/cc/220a/system/snd-cm/cm-2.6.0/src/midi1.scm
; Loading: /home/cc/220a/system/snd-cm/cm-2.6.0/src/midi2.scm
; Loading: /home/cc/220a/system/snd-cm/cm-2.6.0/src/midi3.scm
; Loading: /home/cc/220a/system/snd-cm/cm-2.6.0/src/data.scm
; Loading: /home/cc/220a/system/snd-cm/cm-2.6.0/src/scales.scm
; Loading: /home/cc/220a/system/snd-cm/cm-2.6.0/src/spectral.scm
; Loading: /home/cc/220a/system/snd-cm/cm-2.6.0/src/patterns.scm
guile> (keynum 440.0 :hz)
69.0


Typing directly to guile isn't much fun when things get beyond a simple expression, so later this document I'll show working in an editor. For now, treat these code snippets as continuations of the session just above, i.e., they already have cm loaded and they accumulate their definitions from one to the next. Note that a preceding semicolon says to ignore the comments on the rest of the line.


define a symbol x and give it the value 2

guile> ; variable definition
(define x 2)
guile> (+ 2 x)
4

set an already defined symbol to a different value, now 99

guile> ; variable setting
(set! x 99)
guile> (+ 2 x)
101

procedures are used to encapsulate useful custom behavior, so here's one that adds 2 to a number. If define sees two arguments with a list as the first argument, it takes the first element of the list as the name of a new procedure and following elements as the procedure's arguments. The second argument to define is the new procedure's body. The new procedure creates a new evaluation context, so we can reuse the variable name of x. It is local to the new procedure and distinct from the one at the top-level.

guile> ; procedure definition
(define (add2 x) (+ 2 x))
guile> (add2 100)
102
guile> (add2 x)
101

boolean value is a logical value, not a number, #t = true and #f = false

guile> ; variables can hold whatever, e.g., the value for true
(set! x #t)
guile> (not x)
#f

guile complains if you try to add 2 to #t and gets all wordy about it, but no problem, we continue right from there...

guile> ; errors occur if the wrong type is applied to an operation
(add2 x)
standard input:18:18: In procedure + in expression (+ 2 x):
standard input:18:18: Wrong type argument: #t
ABORT: (wrong-type-arg)
 
Type "(backtrace)" to get more information or "(debug)" to enter the debugger.
guile>

Ok, data types we have just seen: numbers, procedures, lists, booleans... there are test procedures to determine any of these, just add a ?

guile> (number? x)
#f
guile> (boolean? x)
#t
guile> (procedure? x)
#f
guile> (procedure? add2)
#t

There are many more, so please give a good read to

2  Data types (from Teach Yourself Scheme in Fixnum Days by D. Sitaram, which I'll continue to reference)

Expressions can be nested, so here's a one-liner that's a useless conversion to keynum and back to hertz all in one expression. For the dictionary of available musical symbols and procedures that we'll be using see CM


guile> (hertz (keynum 440.0 :hz))
440.0