CS135-lecture-20210227

Functional Programming #

image_2021-02-27-09-34-46 image_2021-02-27-09-36-09

Other functions may write to this.sum, so this could be incorrect in the future.

image_2021-02-27-09-36-53

Any loop can be turned into a recursively structured function.

image_2021-02-27-09-38-56 image_2021-02-27-09-41-27 image_2021-02-27-09-43-24 image_2021-02-27-09-49-18 image_2021-02-27-09-51-19 image_2021-02-27-09-54-55 image_2021-02-27-09-57-47 image_2021-02-27-09-58-31 image_2021-02-27-09-58-45

Example of pow #

int pow(int x, int y)
    if (very small)
        solve directly
    else
        solve with smaller_pow

So when is exponentiation very small? This is the base case, where y = 0.

int pow(int x, int y)
    if (y == 0)
        return 1
    else
        solve with smaller_pow

Now we need to figure out the else branch, we know that x^y = x^(y-1) * x.

int pow(int x, int y)
    if (y == 0)
        return 1
    else
        return x * pow(x, y - 1)

Intro to Racket #

racket-lang.org

wescheme.org

Racket is a form of scheme, and scheme is a form of Lisp.

A method definition (which just calls the built-in sting-append).

(define (my-concat s1 s2)
    (string-append s1 s2))

So we can call this function like:

(my-concat "abc" "def")     ; "abcdef"

Lets define a strlen function:

(define (strlen s)
    (if (= 0 (string-length s))
        0
        (+ 1 (strlen (substring s 1)))))

Yes, this is calling a built in string length function, but its just displaying how a recursively called function is setup.

(strlen "")         ; 0
(strlen "a")        ; 1
(strlen "abc")      ; 3

Racket non-list examples #

Lists are used a lot as a primary data structure in lisps.

A factorial function #

(define (fact n)
    (if (= n 0)
        1
        (* n (fact (-n 1)))))
(fact 0)        ; 1
(fact 1)        ; 1
(fact 2)        ; 2
(fact 10)       ; 3628800

Fibonacci numbers #

We can utilize the cond function, used like this:

(cond (bool expr)
      (bool expr)
      ...
      (else expr))

This is equivalent to a nested if. cond goes one by one and checks each boolean expression, and if true it replaces with expr. The ... means that there can be any number of expressions to check, this is like a switch. As soon as it finds the first true it executes the replacement then ends. At least one thing has to evaluate to true otherwise you’ll get a runtime error, so we can end with an else.

(define (fib n)
    (cond ((= n 0) 1)
          ((= n 1) 1)
          (else (+ (fib (- n 1)) (fib (- n 2))))))

So we can test this:

(fib 0)         ; 1
(fib 1)         ; 1
(fib 2)         ; 2
(fib 3)         ; 3
(fib 4)         ; 5

String reverse #

If given "abc", it should go to "cba". To test for string equality we can use built in string=?, “string equal huh?”. We can use substring to cut the string down, and string-append to append. "cba" = "cb" + "a"

(define (strev s)
    (if (string=? s "")
        s
        (string-append (strev (substring s 1)) (substring s 0 1))))

We can test now:

(strev "")      ; ""
(strev "a")     ; "a"
(strev "ab")    ; "ba"
(strev "abc")   ; "cba"

There is a built in called check-expect, which we can use to test.

(check-expect (strev "abc") "cba")

When you run this, if you see nothing then it works correctly. If it fails you will see the explanation in the output.

writeSequence problem from practiceit #

image_2021-02-27-12-45-19

Note that if you call the sequence on 8, the center is the 6 sequence, then you divide 8 but 2 and round up to get the outside number. We can explicitly change the number to a string with number->string.

(define (ws n)
    (cond ((= n 1) "1")
          ((= n 2) "11")
          (else (string-append (number->string (ceiling (/ n 2))) (ws (- n 2)) (number->string (ceiling (- n 2)))))))

So we can test this to see if its working:

(ws 1)          ; "1"
(ws 2)          ; "11"
(ws 3)          ; "212"
(ws 4)          ; "2112"

Racket under the hood #

Whenever Racket encounters a define in its top down compilation, it stores it in a table. When it calls a function call, it can be thought of as a constant replacing of definition names with its implementation. So a functions name gets replaced by its value. This is easy to think about with single value definitions, like (define n 1), but when a function is defined all the parameters are replaced in the replacement as well.

So if you have this definition:

(define (listlen xs)
    (if (empty? xs)
        0
        (= 1 ( listlen (rest xs)))))

And you call the function like:

(listlen '(1 2 3))

listlen is actually being replaced with:

(if (empty? '(1 2 3))
    0
    (+ 1 (listlen (rest '(1 2 3)))))

Which is then replaced by

(+ 1 (listlen (rest '(1 2 3))))
(+ 1 (listlen `(2 3)))

and so forth.

Debugging in DrRacket #

We can click step in DrRacket to open up a stepper window, that highlights the next substitution that will happen.

image_2021-02-27-13-13-43 image_2021-02-27-13-14-17 image_2021-02-27-13-14-55 image_2021-02-27-13-15-16 image_2021-02-27-13-15-39 image_2021-02-27-13-16-16 image_2021-02-27-13-16-27 image_2021-02-27-13-16-40 image_2021-02-27-13-17-06 image_2021-02-27-13-17-17

This continues on until the base case…

image_2021-02-27-13-18-02 image_2021-02-27-13-18-11 image_2021-02-27-13-18-25