An Introduction to Collective Algorithmic Music Composition

An Introduction to Scheme: Data Types

Data is a precious thing and will last longer than the systems themselves. - Tim Berners-Lee

Data can be classified in different ways. For example, we can classify numbers and text in different categories or we can classify if the type is a certain type of number such as an integer or real number. Different data can be used for different operations and may have different meanings, also data can be stored in different manners, thus, data types are a useful classification that allows programmers to deal with data more efficiently. This section will

Booleans

Boolean values (true or false) are represented in Scheme as #t and #f. To test if a variable is a boolean, we can use the boolean? predicate.

; Test if #f is a boolean value.
(boolean? #f)
; => #t

The preceding code would return true because #f is a boolean.

Characters

Characters are objects that represent printed characters, such as letters, digits, spaces and newlines.

In Scheme, characters are expressed like this:

#\space
#\3
#\a

To test if a variable is a character, we can use the char? predicate. If the variable is a character, the procedure returns #t.

; Test if #\a is a character.
(char? #\a)
; => #t

Characters can be converted to integers (ASCII code) and vice versa.

; Returns the integer value associated with the char value.
(char->integer #\A)
; => 65

; Returns the char value associated with the integer value.
(integer->char 65)
; => #\A

Strings

A string is a sequence of characters.

; To test if a variable is a string, we can use the string? predicate. 
; If the variable is a string, the procedure returns \#t.
(string? "hello")
; => #t

; To find the length of a string use the string-length procedure:
(string-length "hello")
; => 5

; To append a sequence of strings use the string-append procedure:
(string-append "hello" " " "world!")
; => "hello world!"

; The string-ref procedure returns a character for a given position:
(string-ref "hello" 1)
; => #\e

; The substring procedure returns an inner sequence of a string:
(substring "hello" 2 4)
; => "ll"

; To convert a string to a list of characters:
(string->list "hello")
; => (#\h #\e #\l #\l #\o)


; To make a new copy of a string use the string-copy procedure:
(string-copy "hello")
; => "hello"

Symbols

Symbols are unique sets of character sequences. Symbols are not self-evaluating.

; To test if a variable is a symbol, we can use the symbol? predicate. 
; If the variable is a symbol, the procedure returns \#t.
(symbol? 'hello)
; => #t

; To convert a symbol to a string, use the symbol->string procedure.
(symbol->string 'hello)
; => "hello"

; To convert a string to a symbol, use the string->symbol procedure.
(string->symbol "hello")
; => hello

Numbers

Scheme provides a set of procedures and operations for working with numbers. Some of the most commonly used operations are:

;  n = 2
(define n 2)

; is n a number?
(number? n)
; => #t

; is n a complex number?
(complex? n)
; => #f

; is n a real number?
(real? n)
; => #t

; is n a rational number?
(rational? n)
; => #f

; is n an integer?
(integer? n)
; => #t

; is n zero?
(zero? n)
; => #f

; is n a positive number?
(positive? n)
; => #t

; is n a negative number?
(negative? n)
; => #f

; is n even?
(even? n)
; => #t

; is n odd?
(odd? n)
; => #f

Mathematical Procedures

; absolute value
(abs -4.2)
; => -4.2

; acos
(acos 0.2)
; => 1.369438406004566

; asin
(asin 0.2)
; => 0.2013579207903308

; atan
(atan 0.2)
; => 0.19739555984988078

; rounds to the top
(ceiling 1.1)
; => 2

; cosine
(cos 3) 
; => -0.9899924966004454

; exponential
(exp 1)
; => 2.718281828459045

; exponent
(expt 2 3)
; => 8

; rounds to the floor
(floor 1.7)            
; => 1

; logarithm
(log 2)
; => 0.6931471805599453

; maximum
(max 3 5 2 1)
; => 5

; minimum
(min 3 5 2 1)
; => 1

; modulo
(mod 3 2)
; => 1

; round
(round 1.3)
; => 1

; sine
(sin 1)
; => 0.8414709848078965

; square root
(sqrt 4)
; => 2

; tan
(tan 1)
; => 1.5574077246549023

; truncate
(truncate 1.1)
; => 1

Lists and Pairs

A pair consists of exactly two values. Pairs can be constructed using cons.

; construct a pair
(cons 1 2)
; => (1 . 2)

; is it a pair?
(pair? (1 . 2))
; => #t

Lists are Scheme's primary data type. Lists are recursively defined--they are either a constant null, or a pair whose second value is a list.

; define and construct a list
(define my-list (cons 1 '(2 3)))
; => (1 2 3)

; is it a list?
(list? my-list)
; => #t

Lists can also be constructed with the list procedure.

; list procedure
(list 1 2 3)
; => (1 2 3)

To access the element of a list we can use different operations such as list-ref, car and cdr.

; define a new list
(define my-list (list 1 2 3 4 5))

; get the first element of the list using car.
(car my-list)
; => 1

; get the last elements of the list using cdr.
(cdr my-list)
; => (2 3 4 5)

; car and cdr can be combined to access different elements
(cdr (cdr my-list))
; => (3 4 5)

; it can also be written like this
(cddr my-list)
; => (3 4 5)

; another example
(car (cdr (cdr my-list)))
; => 3

; it can also be written like this
(caddr my-list)
; => 3

; get a specific element of a list.
(list-ref my-list 3)
; => 4

; get the tail of the list.
(list-tail my-list 3)
; => (4 5)

; append lists.
(append '(1 2) '(3 4 5))
; => (1 2 3 4 5)

Vectors

Vectors are very similar to lists but they are indexed by non-negative integers and if they are used properly they may require less space and are faster than lists.

; vector can be created with the make-vector function.
(make-vector 3 "hola")
; => #("hola" "hola" "hola")

; get a specific element of a vector.
(vector-ref #(1 2 3) 1)
; => 2

; get the length of a vector.
(vector-length #(1 2 3 4 5))
; => 5