Planting Flowers in Guile

by Muto — Tue 13 February 2018

Planting Flowers in Guile

Guile is a sugary sweet programming language! We can do a lot of cool things in it, so let's jump right in!

Getting Started

Guile can be installed from the official downloads page. Guile comes with something called "The REPL", which stands for "Read, Evaluate, Print, Loop", as in "Read the user's input, Evaluate it, Print the output, and repeat the process". Start the REPL by opening a terminal and typing:

guile

After hitting Return, you'll be greeted with a prompt that looks sort of like:

scheme@(guile-user)>

Welcome to the REPL! Let's do some basic programming.

Math & Strings

(First off, note that indentation is ignored by Guile. Spaces and tabs (known as "whitespace") don't matter)

A string is a bunch of letters. "Hello" is a string. To make Guile say something, we use (display). Open the REPL and type:

(display "Field of tulips")

The parenthesis () are necessary. Once this executes, you'll be greeted with the not-so-surprising output "Field of tulips"!

You can do math fast in the REPL. To add a few numbers, just use a plus sign (+) and any amount of numbers afterwards:

(+ 2 3 5)
;;Two semicolons is a comment.
;;Comments are for humans to read.

The reason we use the "addition operator" (+) at the left side and all the numbers on the right is because, if we wanted to add a lot of numbers, most programming languages would look like:

1 + 2 + 4 + 6 + 22 + 35

Well, that's a lot of plus signs! But in Guile it's very easy and clean:

(+ 1 2 4 6 22 35)

This may take some time to get used to. Just time, that's all it is!

Guile can also multiply, divide and subtract

(* 2 6)
(/ 6 2)
(- 6 2)

If we want to do something snazzy like "4 + 2 - 6", we can do that, too!

(- (+ 4 2) 6)
;;The output is 0 because 4 + 2 is 6 and 6 - 6 is 0

Readline

You know how most terminals have "tab completion" and "command history"? The REPL has that, too, it's called Readline! It's not activated by default for various reasons, but it's recommended that we activate it! In a text editor, in your home directory, create a file named ".guile" (it might already exist), inside that, at the very bottom, type:

(use-modules (ice-9 readline))
(activate-readline)

We're all done! We'll never need to worry about this again!

Lists

A list is a bunch of... things. Think of a flower bed, we have a tulip, a rose, a daisy, and a sunflower. We can start a list by using an apostrophe '

'(tulip rose daisy sunflower)

Well now we have a list! If we type:

(car '(tulip rose daisy sunflower))

You'll notice that only tulip shows up. This is because "car" only gives us the first element in a list.

car has an evil twin, too! "cdr" (pronounced "could-er") that says "give me everything except for the first element!"

(cdr '(tulip rose daisy sunflower))

Well that's nice, but we can't do much with it! The REPL may be nice for just doing small things, but it's not for writing long programs (if you make a single syntax error in the REPL, you have to start all over!). For that we use .scm files! Lets put this knowledge to good use!

Definitions

For this bit, open up a text editor. My favourite is Emacs because it's obviously the best editor for Guile! You should use it, too (okay fine, you can use whatever editor you want.)

If you want to use the REPL inside Emacs, try Geiser. Geiser supports syntax highlighting! If you want a colorful REPL but don't use Emacs, try guile-color!

Start up a new file called "flowers.scm". Guile files can be named anything as long as they have the extension ".scm" at the end. (the SCM is short for "Scheme" because Guile is part of the Scheme family of languages, but you don't need to worry about that.)

Inside the file, type the following:

(define flowers '(tulip rose daisy sunflower))
(define repcar
   (cons 'lily (cdr flowers)))

This code says "Define a variable called 'flowers'. The variable contains a list.

Define a new procedure called repcar (short for ReplaceCar)

Cons the element 'lily onto the cdr of 'flowers' (cons means 'Take this and put it on to the beginning of that)

Now you can run the program by opening a terminal and typing

guile flowers.scm

You should see the output "(lily rose daisy sunflower)", which is exactly what we wanted!

Lambda

Lambda is a gem indeed, it acts as a way to add inputs to our procedures ((define) creates procedures). Lets start with an example. Say we want to find the square root of a number (any number multiplied by itself). We can write a function that allows us to use any number! Open up a new file called "mysquare.scm", and inside, type:

(define mysquare
  (lambda (x)
    (* x x)))

This procedure takes a number and squares it. Let's try it out! Open your terminal & type

guile

From there, type

(load "mysquare.scm")

You now loaded your function! In your REPL, use it with

(mysquare 3)

We used 3 for this example, but use any number you want! You should see the desired output (in this case, 9)

Recursion

In this bit, I want to talk about recursion. Recursion is a procedure that "does itself" until a certain condition is met. That sounds weird but you can think of it like a loop. I'm going to give you an example, it'll seem a little odd but I'll explain it after.

Create a file named weeds.scm

(define weeding
  (lambda (new old lat)
    (cond
     ((null? lat)
      (quote ()))
			  
     (else
      (cond
       ((eq? (car lat) old)
        (cons new (cdr lat)))

       (else
        (cons (car lat)
              (weeding new old (cdr lat))))))))) 

Now inside your REPL, load it up (with (load "weeds.scm")). While we're here, let's define new, old, and lat.

(define new 'tulip)
(define old 'weed)
(define lat '(rose sunflower weed daisy))

Alrighty. So lat is a list, but we have a weed right where we want to plant our tulip! This is where our recursion comes in!

First we (define weeding) and add a (lambda) with some inputs (new, old and lat)

Next, we use cond (which is short for Conditional). cond asks questions

((null? lat) This one says "Is lat (the list) an empty list?" (often called "the null list") If it is, return nothing at all, because there are no weeds to replace.

Next we use "else", as in "If lat is empty, return nothing, or else, if it isn't empty, do the following:"

(eq? (car lat) old) eq? is short for "equal?". This asks if the car of our list is equal to old (old is 'weed), and if (car lat) is 'weed, cons new onto the cdr of lat (cdr lat is a list itself, and since (car lat) is 'weed, we don't want it, so we attach 'tulip to cdr lat

Else, if (car lat) is not 'weed, do it again, but this time, do it with (cdr lat), which means lat is now '(sunflower weed daisy) instead of '(rose sunflower weed daisy)

Notice that we (cons the car of lat onto our recursion. This is because we only want to get rid of 'weed, not rose or sunflower

This may be a little confusing still, but write it down a few times, change things up, maybe use numbers instead of other things, and you'll find that even though it takes some time to explain, it's quite simple!

A few handy tips

The cdr of a list is always another list, so (cdr '(a b c d e)) is '(b c d e)

So (cdr (cdr '(a b c d e))) is '(c d e)! (car (cdr '(a b c d))) is (b).

car and cdr may be a little weird to get used to, but they're very handy!

(cons) adds something to the start of a list. cons always has two arguments, an element and a list. (cons 'a '(b c d)) is '(a b c d).

(cons 'a (cons 'b (cons 'c ()))) is the same as '(a b c)

Pattern Matching

Pattern matching is a helpful method used to... Well, match patterns! We start with loading the (ice-9 match) module. It's included in the default Guile installation, so there's no need to download any external library!

After the match module is loaded, we tell Guile "I want you to find needle x in haystack y!" Take this program as an example:

(use-modules (ice-9 match))

(match 3
  (1 'one)
  (2 'two)
  (3 'three)
  (4 'four))

Since the "case" we specified is 3, our output is "three"! Pattern matching makes for beautiful, readable code. This is what our file would have looked like without pattern matching:

(define patmat
  (lambda (a b)
    (cond
     ((null? b) (quote ()))
     (else
      (cond
       ((eq? a (car (car (car b))))
	(car (car (car b))))
       (else
	(patmat a (cdr b))))))))

(define mylist
  '(((1) 'one)
   ((2) 'two)
   ((3) 'three)
   ((4) 'four)))

(patmat 3 mylist)

Well, that's a little cryptic! You can probably tell now that pattern matching is very nice to have!

Let's write our match program with a lambda, to give us the option to use more numbers than just 3!:

(use-modules (ice-9 match))

(define patmat
  (lambda (a)
    (match a
      (1 'one)
      (2 'two)
      (3 'three)
      (4 'four)
      (else 'no))))

Very nice! Lets run some tests real quick:

(patmat 2)
(patmat 4)
(patmat 8)

Alrighty, let's go a bit deeper! Let's find a pattern and add the two middle numbers together! We can do this with letter variables:

(use-modules (ice-9 match))

(define patmatch
  (match '(1 2 3 0)
      ((1 x y 0) (+ x y))
      ((2 x y 8) (+ x y))
      ((5 x y 9) (+ x y))))

Pretty cool, pretty cool!

There's a lot of cool things you can do with pattern matching, but it would be too long to explain them all in this tutorial. If you want to learn some extra tips, I'd recommend This article by Ceaude or This short video introduction. Anyway, we're nearing the end of the article, so let's continue...

A text adventure game!

Let's take what we learned & create a short text adventure game. Most of it is pattern matching (the same method can be used to make an adventure game much, much larger!)

First, here's the "game.scm" file:

(use-modules (ice-9 match))

(define inventory
  '(rose lily poppy))

(display "You stand in a field of rolling hills, dark grass, and flowers.
It's drizzeling a little bit, the cool breeze gently ruffles your hair.
 i: Leave and go inside the house.
 t: Pick tulip
 l: Pick lilac
 d: Pet dogn
 >")

(match (read-char)
   (#\i (display "You went inside. -The end"))
   (#\t (display "You picked a tulip!") (cons 'tulip inventory))
   (#\l (display "You picked a lilac!") (cons 'lilac inventory))
   (#\d (display "You petted a nearby dog! Good puppy!")))

#\ tells the computer "The following letter is a character, not a variable or a list.", so when you press "A" on your keyboard, Guile sees "#\A".

(read-char) is a way to say "Stop the program and 'read' the next character from the user's input!"

This adventure is very short because I want the article to be very short. There are no Good ending/Bad ending's or different paths. As a word of advice: when making an adventure game, you can break it down to multiple files by using (load "filename.scm"), for instance:

(#\i (load "InsideHouse.scm"))

I hope this all makes sense! If it doesn't, don't sweat it! It just takes time.

Beautiful resources

If you want to master Guile, try these resources! Guile is part of the Scheme family, and as such, books on Scheme are also books on Guile! Every example in them can be used in Guile (more or less)!

The Little Schemer. This book is fun and short! You'll learn to master the basics of Scheme, which is pretty much all Scheme is. Practice the methods used in this book & you'll become brilliant in no time! (Also try the sequel The Seasoned Schemer, admittedly I have never read it)

Structure and Interpretation of Computer Programs. This one is a little bit dry & technical, but if you're a dork like me, you'll definitely enjoy it! Also it'll look good on your resume!

Learn Scheme in 15 Minutes by Artanis. This one is extremely well written & the Artanis framework itself is wonderful (and written in Guile)! Check it out!

Having Fun with Guile by Chris Webber! This short online tutorial is super fun and short!

Ceaude - Programming Language Adventures is a blog with very well written & straight forward articles!

David Thompson's collection of Guile frameworks, Seriously, my website was written with his site generator & there are tools that allow you to easily make video games on the fly!

I hope this helped at least a little bit! After all this talk about flowers, I really feel like wearing some flowery perfume & steeping myself a flowery tea, you can do the same if you like! Until next time, stay kind! -Muto