Scheme I

Intro into Functional Programming

What is Functional Programming

  • All the languages you've used up until now were most likely imperative or object-oriented
  • Based on the mathematical idea of a function
  • Pure Functional Programming doesn't allow mutable objects or assignment into variables
    • Haskell is a pure functional language
  • Most functional languages today allow variables and may allow mutable objects
  • Inspired by Lambda Calculus
  • Rely more on recursion than inheritance

Mathematical Review

  • Mathematically, a function is a mapping from a domain to a range
  • Each element of the domain is always mapped to the same element in the range
  • A mathematical function does not cause side effects, it only takes in parameters, and returns the corresponding element in the range
  • Lambda calculus is one way to express functions
    • The cube of a number would be written as $\lambda(x)x*x*x$

A Bit of Background

  • While many programming languages we have learned are descendents from the same "tree" , the functional programming languages have developed more or less in parallel
    • This is starting to change as traditional imperative langauges adopt functional paradigms
    • We will look at this in a few lectures
  • Lisp ( LISt Processing ) was invented in 1959, making it the second oldest langauge still in use today
  • Many newer languages are slight variations on Lisp and are often called dialects because with a few changes, a program could be run in Lisp

Scheme

  • A Dialect of Lisp invented in 1975
  • Is smaller and has a simpler syntax than Lisp
  • Is typeless
  • Very popular in education, especially in intro to CS classes (MIT until circa 2009, still used at Yale)

A first look at scheme

In [117]:
(+)
Out[117]:
0
In [118]:
(+ 1 2)
Out[118]:
3
In [119]:
(+ 1 2 3)
Out[119]:
6
In [120]:
(*)
Out[120]:
1
In [121]:
(* 2 3 4)
Out[121]:
24
In [122]:
(-)
Traceback (most recent call last):
  File "In [122]", line 1, col 1, in '-'
  File "In [122]", line 1, col 1
RunTimeError: incorrect number of arguments to -

In [128]:
(modulo 14 2)
Out[128]:
0

Scheme on GL

  • Like Lisp, scheme has evolved into many dialects
    • To be considered a dialect of scheme, most programmers agree that it should follow the Revised$^5$ Report on the Algorithmic Language Scheme (R5RS)
  • Scheme files end in .ss or .scm
  • The version on GL is called PLT Scheme and run using mzscheme
    • This dialect no longer exists
    • The creators felt that their product evolved to a point to be called Scheme, even though they still consider it a dialect of Lisp and a descendent of Scheme
    • It is now called Racket
  • To exit the REPL type (exit)

Syntax

  • In general the syntax is (function parameter parameter parameter)
    • Parentheses get messy, but use an editor that has parentheses matching and lots of spacing and indentation, and you will be ok!
  • Identifiers have a much wider range of characters to use
    • Can contain letters, digits, +, -, *, /, <, =, >, :, \$, %, ^, &, _, ~, @, ?, !, and .
    • Can't start with anything a number could start with
      • +, - are special function names already though
    • Case might matter
      • In R5RS case didn't matter
      • In R6RS case does (This is what is on GL by default)

Naming Conventions

  • Because of the wide variety of symbols allowed in an identifier, naming conventions have emerged than can tell us alot about what a function might do
    • A predicate function usually ends in ? (odd?)
    • A function that operates on a string or char is precded by char- or string-
    • When converting betweeen objects we can use the -> symbol
    • A function that has a side effect (which should be rare) ends in !

Data Basics

  • In Scheme, everything is an atom or a list
  • An atom can be an integer, or an identifier, or a string, or…
  • A list is a left parenthesis, followed by zero or more S-expressions, followed by a right parenthesis
  • An S-expression is an atom or a list
    • Example: ()
    • (A (B 3) (C) ( ( ) ) )

Datatypes

  • A list is the primary datatype in Scheme
  • Scheme also has vectors which are denoted like #(1 2 3 4)
    • A vector is an immutable fixed length list
  • Strings are delimited by double quotes
  • Characters are denoted with #\ as in #\a
  • Numbers can be integers, fractions, decimals, or scientific notation.
  • ; Is the comment symbol
  • True is represented by #t, False by #f
    • Anything besides #f will be evaluated to true

Datatype Examples

In [129]:
(display `(1 2 3 4))
(1 2 3 4)
In [130]:
(display 10/20)
(display "\n")
(display 1)
(display "\n")
(display 100.111111)
1/2
1
100.111111
In [138]:
#(1 2 3 4)
Out[138]:
#4(1 2 3 4)
In [137]:
(display #\a)
#\a

Quoting

  • In most functional programming languages, data and code are the same
    • To prevent the execution of code, we apply a special form known as a quote
    • We can either type the word quote, use the backtick `, or a single quote '
In [139]:
`(1 2 3 4)
Out[139]:
(1 2 3 4)
In [141]:
(quote (1 2 3 4))
Out[141]:
(1 2 3 4)
In [142]:
(1 2 3 4)
Traceback (most recent call last):
  File "In [142]", line 1, col 1, in 'application'
  File "In [142]", line 1, col 1
RunTimeError: attempt to apply non-procedure '1'

Evaluation

The evaluation rules of scheme are as follows

  • Numbers, strings, #f, #t, all evaluate to themeselves
  • A list is taken to be a function call by default, with the first item the function and the remaining items the parameters
  • A special form such as quote or define are not evaluated
  • Evaluation can be forced with the eval function

Evaluation Examples

In [143]:
(define a `(+ 10 20 30 40))
In [144]:
a
Out[144]:
(+ 10 20 30 40)
In [145]:
(eval a)
Out[145]:
100

Basic Functions

  • Three of the most imporant functions in Scheme deal with constructing and examining lists
  • car returns the first element in a list
  • cdr returns the rest of it
  • cons builds a list by prepending its first parameter to its second

Basic Function Examples

In [146]:
(car `(1 2 3 4))
Out[146]:
1
In [147]:
(cdr `(1 2 3 4))
Out[147]:
(2 3 4)
In [148]:
(cons 1 `(2 3 4))
Out[148]:
(1 2 3 4)

Basic Function Practice

Use cons to create:

  • (1 2 3)
  • ((1 2) 3)
  • (1 (2 3))
  • ((1 2) (3))
  • ((1)(2)(3))
  • (((1)) (2) 3)
In [149]:
(cons 1 (cons 2 (cons 3 ())))
; On GL it would be (cons 1 (cons 2 (cons 3 null)) due to dialectal differences
Out[149]:
(1 2 3)
In [153]:
(cons (cons 1 (cons 2 ())) (cons 3 ()))
Out[153]:
((1 2) 3)
In [161]:
(cons 1 
      (cons (cons 2 (cons 3 ())) ())
)
Out[161]:
(1 (2 3))
In [195]:
(cons (cons 1 (cons 2 ())) (cons (cons 3 ()) ()))
Out[195]:
((1 2) (3))
In [200]:
(cons (cons 1  ()) (cons (cons 2 ()) (cons (cons 3 ()) () )))
Out[200]:
((1) (2) (3))
In [205]:
(cons (cons (cons 1 ()) () ) (cons (cons 2 ()) (cons 3 ())))
Out[205]:
(((1)) (2) 3)

Basic Function Practice

Get 3 out of the following expressions:

  • (((3)) (1) 2)
  • ((1) (3) ((2)))
  • ((1 3 2) 5)
In [165]:
(car (car (car `(((3)) (1) 2))))
Out[165]:
3
In [166]:
(caaar `(((3)) (1) 2))
Out[166]:
3
In [169]:
(car (car (cdr `((1) (3) ((2))))))
Out[169]:
3
In [171]:
(caadr `((1) (3) ((2))))
Out[171]:
3
In [173]:
(car (cdr (car `((1 3 2) 5))))
Out[173]:
3
In [174]:
(cadar `((1 3 2) 5))
Out[174]:
3

More Functions

  • eq? Tests the equality between two atoms
  • equal? Tests the equality between s-expressions
In [206]:
(eq? "the" "the")
Out[206]:
#f
In [176]:
(eq? `t 't)
Out[176]:
#t
In [177]:
(equal? "the" "the")
Out[177]:
#t
In [178]:
(equal? (cons 1 (cons 2 (cons 3()))) `(1 2 3))
Out[178]:
#t

Even More Functions

  • Using cons can get cumbersome, so the function list will make a list out of all the arugments
  • Concatinating two or more lists is done with append
In [179]:
(list 1 2 3 4)
Out[179]:
(1 2 3 4)
In [180]:
(append `(1 2) `(3 4))
Out[180]:
(1 2 3 4)
In [181]:
(append `(1 2) `3 `4)
Traceback (most recent call last):
  File "In [181]", line 1, col 1, in 'append'
  File "In [181]", line 1, col 1
RunTimeError: append called on incorrect list structure 3

In [184]:
(append `(1 2) `(3) `("s"))
Out[184]:
(1 2 3 "s")

List practice

Basic Function Practice

Use list to create:

  • (1 2 3)
  • ((1 2) 3)
  • (1 (2 3))
  • ((1 2) (3))
  • ((1)(2)(3))
  • (((1)) (2) 3)
In [185]:
(list 1 2 3)
Out[185]:
(1 2 3)
In [186]:
(list (list 1 2) 3)
Out[186]:
((1 2) 3)
In [187]:
(list 1 (list 2 3))
Out[187]:
(1 (2 3))
In [208]:
(list (list 1 2) (list 3))
Out[208]:
((1 2) (3))
In [207]:
(list (list 1) (list 2) (list 3))
Out[207]:
((1) (2) (3))
In [189]:
(list (list (list 1)) (list 2 ) 3)
Out[189]:
(((1)) (2) 3)