123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309 |
- (section
- :title [Opening the toy box]
- (p [Let's build ourself a little toy box for us to play around with.
- Enter the following at your Guile REPL:])
- (frame
- (prog :line #f
- "(define toy-box '(robot teddy-bear doll-with-comb toy-soldier))"))
- (p [If we forget what's inside our toy box, we can always look inside it.])
- (frame
- (prog :line #f
- "scheme@(guile-user)> toy-box
- ;; => (robot teddy-bear doll-with-comb toy-soldier)"))
- (p [Our friend ,(code "toy-box") here is a variable, and the information
- it references is called a "list", and lists are at the heart of
- Scheme (and indeed Lisp, which stands for "list processing", which
- Scheme is a variant of).
- We can verify that it is indeed a list:])
- (frame
- (prog :line #f
- "scheme@(guile-user)> (list? toy-box)
- ;; => #t"))
- (p [And indeed it is!])
- (p [Of course, the fun of the toy box is not the box itself, but the toys.
- So, let's pull out the first toy from the box:])
- (frame
- (prog :line #f
- "scheme@(guile-user)> (car toy-box)
- ;; => robot"))
- (p [That looks like the toy closest to the top of our box indeed.
- But why is that command called ,(code "car")?
- We weren't trying to pull a toy car from the box!
- "car" is a term with some history in lisps (it stands for
- "Content Address Register") but that history is not important
- to us at the very moment.
- For now, every time you see ,(code "car"), you can think of it as meaning
- "first".])
- (p [Of course, there are more toys in the box than just that robot.
- What's under the robot in the box?])
- (frame
- (prog :line #f
- "scheme@(guile-user)> (cdr toy-box)
- ;; => (teddy-bear doll-with-comb toy-soldier)"))
- (p [Another strange command... ,(code "cdr")!
- ,(code "cdr") is prounounced "could-er" (and also is a historical name,
- standing for "Content Decrement Register", which is again not
- important at the moment).
- For now, every time you see ,(code "cdr"), you can think of it as
- meaning "rest", giving you the rest of the list.])
- (p [We can see that at the top of the list returned with "cdr"
- is a nice looking teddy-bear.
- Can we pull that off the top?
- Indeed, we can by nesting the commands!])
- (frame
- (prog :line #f
- "scheme@(guile-user)> (car (cdr toy-box))
- ;; => teddy-bear"))
-
- (p [Horray!
- What a nice looking teddy-bear.])
- (p [One thing we can notice from the above is that we nested the call to
- cdr inside the call to car.
- We can understand how this works by doing the substitution
- manually:])
- (frame
- (source :language scheme
- (prog :line #f
- (string-join
- '("(car (cdr toy-box))"
- ";; Substitute in toy-box"
- "(car (cdr '(robot teddy-bear doll-with-comb toy-soldier)))"
- ";; Pull out the rest of the list via cdr"
- "(car '(teddy-bear doll-with-comb toy-soldier))"
- ";; Pull the first item off the top with car"
- "'teddy-bear")
- "\n"))))
- (p [This is how a lot of Guile/Scheme/Lisp looks:
- expressions nested inside other expressions.
- The parentheses help you understand the beginning and end of an
- expression.
- For much of the programming you will do with Guile, you can figure
- out what's going on by doing the substitutions in your head like
- above.
- (Not everything works via substitution, but discussing that is
- beyond the scope of this tutorial!)])
- (p [(There are other, easier to read ways to pull out items from a list
- (or toys from a toybox).
- We will get to them later.)])
- (p [What if we want to add a toy to our toybox?
- Luckily we have a little friend named ,(code "cons"), which is used
- to construct (or add to) lists.
- Let's cons a new toy to our toybox now!])
- (frame
- (prog :line #f
- "scheme@(guile-user)> (cons 'bouncy-ball toy-box)
- ;; => (bouncy-ball robot teddy-bear doll-with-comb toy-soldier)"))
- (p [It's so nice to see that bouncy-ball with its toy friends!
- But wait, this is surprising:])
- (frame
- (prog :line #f
- "scheme@(guile-user)> toy-box
- ;; => (robot teddy-bear doll-with-comb toy-soldier)"))
- (p [Huh?
- When we ran cons, we got back a new list of toys that included
- our bouncy-ball, but when we look back inside of toy-box, we
- see it isn't there!
- This is on purpose (and is actually a feature): when we used cons,
- we got back a new list with our old list attached at the end.
- It didn't change our old list to do this... changing our old list
- mean that we "mutated" it.
- (code "toy-box") is a variable, and it still points at our original toy box
- list.])
- (p [Suppose we did want to actully change what toy-box means and have
- it point to something else.
- We could do this.
- Guile has a command named ,(code [set!]) which will let you
- change the value of a variable we already defined.
- Let's try it:])
- (frame
- (prog :line #f
- "scheme@(guile-user)> (set! toy-box (cons 'bouncy-ball toy-box))
- scheme@(guile-user)> toy-box
- ;; => (robot teddy-bear doll-with-comb toy-soldier)"))
- ;; TODO: Move this part to part two of the intro to procedures bit?
- (p [This seems rather convenient!
- And sometimes, it is.
- Unfortunately, assignment and mutation can sometimes cause unexpected
- and unpleasant surprises for us.
- Imagine we were running a program with many friends running around our
- playground at once.
- Our friend Jessica may hear that there's a robot in the box from her
- friend Aaron, and so she may go to retrieve it, but in-between that
- maybe we took the toy out of the box to play with, and Jessica will
- become very confused when she opens the box and doesn't see the
- robot.
- (Maybe she will even think that Aaron lied to her, though of course, we
- really didn't mean to cause that kind of mistake, we just wanted
- our robot!)
- Computer programs run into these same kinds of issues and often times
- have less ideas on what to do when things unexpectedly change around
- them than even we might, and this can lead to all sorts of problems.
- We won't go into details, but procedures that might cause tricky behavior
- like this are said to have "side effects", and in Guile (and Scheme
- generally) the convention is to label these with an exclaimation mark.
- So when you see the explaination mark at the end of ,(code "set!")
- remember that someone is shouting, "this has a side effect, be careful!"])
-
- (p [The good news though is that Guile provides both datastructures that do
- and don't require visible side effects.
- When it comes to lists, you can mutate them, but unless you really need
- to, you probably don't want to or have to!])
- (p [We'll come back to lists a bit more towards the end of the chapter.
- For now, there are some other fun types of data to play with.]))
- (section
- :title [Simple types of toys]
- (p [So far we've worked with two types of data: lists and symbols.
- Of course, there are a lot of other types of data out there!
- But since we've seen symbols, let's start with them.
- (We'll get more into lists (and other ways to group information
- together)later.)])
- (p [All the toys that were in our box were symbols.
- We can create a symbol very easily:])
- (frame
- (prog :line #f
- "scheme@(guile-user)> 'race-car
- ;; => race-car"))
- (p [Symbols are used to stand in for ideas.
- Sometimes lisp programmers use them as "keys" to look up information,
- and lisp programs are technically themselves made mostly out of
- lists and symbols!
- You can test if two symbols are the same with ,(code "eq?"):])
- (frame
- (prog :line #f
- "scheme@(guile-user)> (eq? 'apple 'apple)
- ;; => #t
- scheme@(guile-user)> (eq? 'apple 'orange)
- ;; => #f"))
- (p [Hey wait, what are those ,(code "#t") and ,(code "#f") things?
- Good question!
- These are called "booleans".
- In Guile, ,(code "#t") stands for "true" and ,(code "#f") stands
- for "false".
- Though you should know: in Guile everything that isn't ,(code "#f")
- is considered to be true!])
- (p [It would be nice if we could work with numbers.
- For example, we might like to be able to count how many toys are
- in our toy box.])
- (frame
- (prog :line #f
- "scheme@(guile-user)> (length toy-box)
- ;; => 4"))
- (p [The number we got back is an integer, in other words a whole number
- (which can be positive or negative).
- It's fun to play with integers!])
- ;; @@: Mixing comments and the ";; => foo" style is clearly not nice,
- ;; as evidenced here...
- (frame
- (prog :line #f
- ";; Since Guile uses lisp-style \"prefix notation\", we write
- ;; \"8 + 2\" like (+ 8 2)
- scheme@(guile-user)> (+ 8 2)
- ;; => 10
- ;; Multiplication looks similar:
- scheme@(guile-user)> (* 6 10)
- ;; => 60
- ;; We can include multiple arguments to add or multiply many things at once:
- scheme@(guile-user)> (+ 1 2 3)
- ;; => 6
- ;; And of course we can combine together math expressions
- scheme@(guile-user)> (* (+ 1 2 3) 10)
- ;; => 60"))
- (p [Integers aren't the only kinds of numbers... Guile also has "rational"
- numbers (like fractions) and floating point numbers, or "inexact"
- numbers.
- Unlike in some other languages, Guile tries to keep numbers exact until
- you need to convert them to an inexact form.
- This makes Guile very nice for all sorts of number games!])
- (frame
- (prog :line #f
- ";; Floating point (inexact) numbers
- scheme@(guile-user)> .4
- ;; => 0.4
- ;; We can enter rational numbers by hand
- scheme@(guile-user)> 2/3
- ;; => 2/3
- ;; If we divide, we get back rational numbers
- scheme@(guile-user)> (/ 2 3)
- ;; => 2/3
- ;; ... unless we choose to convert them to inexact form!
- scheme@(guile-user)> (exact->inexact (/ 2 3))
- ;; => 0.6666666666666666"))
- (p [There are more number types available in Guile, but we'll let
- you read the manual to find out more about them.])
- (p [It would be nice to be able to describe our toys to someone.
- What can we use?
- It would be awkward to use symbols to say a whole sentence.
- We would like to be able to say something using a data type
- more befitting our words.
- Of course, words and sentences are made of letters, and in
- Guile, we call those "characters".
- Here is a list of characters:])
-
- (frame
- (prog :line #f
- "scheme@(guile-user)> '(#\\a #\\b #\\c #\\d #\\e #\\f #\\g)
- ;; => (#\\a #\\b #\\c #\\d #\\e #\\f #\\g)"))
- (p [Well, talking to our friends letter by letter sounds very painful.
- Luckily, we have a nice type that deals with text called
- "strings", which "string together" a series of characters.
- And they are very easy to use!])
- (frame
- (prog :line #f
- "scheme@(guile-user)> \"abcdefg\"
- ;; => \"abcdefg\"
- scheme@(guile-user)> (string->list \"abcdefg\")
- ;; => (#\\a #\\b #\\c #\\d #\\e #\\f #\\g)
- scheme@(guile-user)> \"our teddy bear is very fuzzy\"
- ;; => \"our teddy bear is very fuzzy\"
- scheme@(guile-user)> (string-join '(\"hop\" \"skip\" \"jump\")
- \" and a \")
- ;; => \"hop and a skip and a jump\""))
- (p [Those are some interesting kinds of toys to play with.
- Now it's time to learn how to breathe some life into them.]))
|