Scheme III

Recursion

  • Recursion is the prefered method in scheme for processing a list element by element
  • If possible, put the recurrsive call at the end to cause tail recursion
    • This allows a compiler to optimize a recursion function

Recursion Example

In [ ]:
(define member
    (lambda (mem l)
       (cond
        ((null? l) #f)
        ((eq? mem (car l)) #t)
        (else (member mem (cdr l)))
       )
    )
)
In [ ]:
(member 3 `(1 2 3 4))

Recursion Practice

Write a recursive fucntion the returns the length of a list

In [ ]:

Letrec

  • The scope of variables in a let statement is the body of the statement
  • What if we want to define a function in a let statement recursively?
    • letrec expands the scope slightly to include the value of the variable

Letrec example

From The Scheme Programming Language

(letrec ([sum (lambda (ls)
                (if (null? ls)
                    0
                    (+ (car ls) (sum (cdr ls)))))])
  (sum '(1 2 3 4 5)))

Assignment

  • Assignment is possible in Scheme, but there usually isn't a need for it
  • set! is used to update a variable
In [ ]:
(define old+ +)
(set! + -)

Assignment Practice

Rewrite the function below to not use set!

In [ ]:
(define quadratic-formula
  (lambda (a b c)
    (let ([root1 0] [root2 0] [minusb 0] [radical 0] [divisor 0])
      (set! minusb (- 0 b))
      (set! radical (sqrt (- (* b b) (* 4 (* a c)))))
      (set! divisor (* 2 a))
      (set! root1 (/ (+ minusb radical) divisor))
      (set! root2 (/ (- minusb radical) divisor))
      (cons root1 root2))))

Closures

  • Just like Lua, Scheme has closures
  • I think they are actually clearer in Scheme
  • General Layout:
    (define closureName (lambda ()
      (let ((varToClose val))
          (lambda ()
              update varToClose
          )
      )
    )
    

Closure Examples

In [ ]:
(define counter (lambda()
  (let ((count 0))
    (lambda ()
      (set! count (+ count 1))
      count))))
In [ ]:

Closure Practice

  • Write a closure that takes in a variable, and returns a function that takes another variable
    • This function will return greeting + name.
    • (define hi (closure "hello"))
    • (hi " world") results in "hello world"
In [ ]:

Objects

From http://people.cs.aau.dk/~normark/prog3-03/html/notes/oop-scheme_themes-classes-objects-sec.html

In [ ]:
(define (send message obj . par)
  (let ((method (obj message)))
    (apply method par)))

(define point (lambda(x y)
  (letrec ((getx    (lambda () x))
           (gety    (lambda () y))
           (add     (lambda (p) 
                      (point 
                       (+ x (send 'getx p))
                       (+ y (send 'gety p)))))
           (type-of (lambda () 'point))
          )
    (lambda (message)
      (cond ((eq? message 'getx) getx)
            ((eq? message 'gety) gety)
            ((eq? message 'add)  add)
            ((eq? message 'type-of) type-of)
            (else (error "Message not understood")))))))
In [ ]:
(define p1 (point 10 20))
(define p2 (point 1  2))
(send 'gety p1)
(send 'getx p2)
(send 'add p1 p2)

Apply

Last class to pass a list as the parameters to a function I used this trick

(eval (append `(+) x) )

This is a common need, so there is a function than handles this, apply

The general syntax is

(apply function list)

Apply Examples

In [ ]:
(apply + `(1 2 3 4 5))
In [ ]:
(apply * `(1 2 3 4 5))
In [ ]:
(apply string-append `("This" "is" "one"))

Apply Practice

  • Write an expression to test if all the numbers in a list are positive
In [ ]:

Map

What if instead of passing a list as parameters, we wanted to apply a function to each element in the list?

map allows us to do this, returning a list of values from applying the function to each element

The geneneral syntax of map is

(map function list1 list2 ... listn)

Map Examples

In [ ]:
(map abs '(1 2 -3 -4 -5))
In [ ]:
(map + '(1 2 3) '(3 2 1))
In [ ]:
(map (lambda(x) (* x x)) `(1 2 3 4 5))

Map Practice

  • Use a combination of map and apply to concatenate a list of strings seperated by a given character
In [ ]:
In [ ]:

Filtering

  • Filter is like a special type of map.
    • Filter is passed a predicate and a list
    • Given a list, returns the elements of that list that the predicate evaluates for true for
  • General syntax is
    (filter predicate list)
    

Filter Example

In [ ]:
(filter odd? `(1 2 3 4))
In [ ]:
(filter (lambda (x) (string=? (substring x 0 1) "A")) `("Alamo" "alaska" "Baltimore" "Austin" "boston" "Alabama"))

Filter Practice

  • Write an expression that checks if all elements in a list are positive
In [ ]:

Input

  • A file is opened for reading with (open-input-file filename), which returns a handle to the file
  • To read a file use (read handle)
  • Reading is also done recusivley
In [ ]:
(define file (open-input-file "turing.txt"))
(define readFile
  (lambda (p)
    (let f ((x (read p)))
      (if (eof-object? x)
          '()
          (cons x (f (read p)))))))

(readFile file)

Output

  • A file is opened for writing with (open-output-file filename), which returns a handle
    • If the file exists, it returns an error, rather than overwriting it
  • To write to a file use (write object handle)
  • Writing to a file isn't quite as messy
In [ ]:
(define file (open-output-file "schemeOut2.txt"))
(write `("A" "small" "little" "text" "file") file)
In [ ]:
(define file (open-output-file "schemeOut2.txt"))
(map (lambda (x) (write x file)) `("A" "small" "little" "text" "file"))