Lecture 3 Slides - Compound Functions

1 of 39

Lecture 3 (Pre-Recorded)

Compound Functions

2 of 39

Rules of computation in Racket

  • If it’s a constant (a number or string)
    • It’s its own value
    • Return it

  • If it’s a variable name (e.g. a word, hyphenated-phrase, or symbol like +)
    • Look up its value in the dictionary
    • Return (output) it

  • If it has parens
    • (i.e. it looks like "(a b c …)”)
    • Find the values of a, b, c, etc. using these same rules
    • The value of a had better be a function
    • Call it with the values of b, c, etc. as inputs
    • Return its output

3 of 39

How do we make a square?

4 of 39

5 of 39

How do we make a row of squares?

6 of 39

7 of 39

How do we make a grid?

8 of 39

9 of 39

Wow, that’s a lot of typing…

(above (beside (square 50 "outline" "black")

(square 50 "outline" "black")

(square 50 "outline" "black")

(square 50 "outline" "black"))

(beside (square 50 "outline" "black")

(square 50 "outline" "black")

(square 50 "outline" "black")

(square 50 "outline" "black"))

(beside (square 50 "outline" "black")

(square 50 "outline" "black")

(square 50 "outline" "black")

(square 50 "outline" "black"))

(beside (square 50 "outline" "black")

(square 50 "outline" "black")

(square 50 "outline" "black")

(square 50 "outline" "black")))

10 of 39

Wow, that’s a lot of typing…

(above (beside (square 50 "outline" "black")

(square 50 "outline" "black")

(square 50 "outline" "black")

(square 50 "outline" "black"))

(beside (square 50 "outline" "black")

(square 50 "outline" "black")

(square 50 "outline" "black")

(square 50 "outline" "black"))

(beside (square 50 "outline" "black")

(square 50 "outline" "black")

(square 50 "outline" "black")

(square 50 "outline" "black"))

(beside (square 50 "outline" "black")

(square 50 "outline" "black")

(square 50 "outline" "black")

(square 50 "outline" "black")))

Why isn't there some way of telling Racket: "whenever I say quack I really mean 'draw a square in outline mode that's black and is size 50'"...

11 of 39

defining new names

12 of 39

Defining new names

(define name value)

  • Tells system that name now refers to value
    • name must be a valid variable name
    • But value can be an arbitrary expression
  • Has to be executed to take effect
  • Naming is the most basic abstraction mechanism
  • Here we're naming a variableafter we define it, anytime we use this name Racket will use whatever value we stored inside it
  • Example: (define netid "abc1234") means that after I run this line of code, whenever Racket reads the name netid and substitute in the value "abc1234"

13 of 39

Simplifying with names

(define unit(square 50 "outline" "black"))

(above (beside unit unit unit unit)

(beside unit unit unit unit)

(beside unit unit unit unit)

(beside unit unit unit unit))

14 of 39

define isn’t a function

Why?

15 of 39

Rules of computation in Racket

  • If it’s a constant (a number or string)
    • It’s its own value
    • Return it

  • If it’s a variable name (e.g. a word, hyphenated-phrase, or symbol like +)
    • Look up its value in the dictionary
    • Return (output) it

  • If it has parens
    • (i.e. it looks like "(a b c …)”)
    • Find the values of a, b, c, etc. using these same rules
    • The value of a had better be a function
    • Call it with the values of b, c, etc. as inputs
    • Return its output

16 of 39

Special forms

  • Define is a special case that works differently from function calls
    • For a function call you always replace input expressions with their values
    • But if you’re defining a variable, it doesn’t have a value yet!

  • There are a few special kinds of expressions like this, called special forms
    • We’ll learn a few more, but not very many

17 of 39

This...still isn't that nice to write.

(define unit(square 50 "outline" "black"))

(above (beside unit unit unit unit)

(beside unit unit unit unit)

(beside unit unit unit unit)

(beside unit unit unit unit))

18 of 39

How can we do better?

(Don’t say “loop”; we won’t get to those until next time

19 of 39

Name the row

(define unit (square 50 "outline" "black"))

(define row (beside unit unit unit unit))

(above row row row row)

20 of 39

Your client called

Now they also want one with circles rather than squares

21 of 39

New and improved

(define circ-unit (circle 25 � "outline" � "black"))

(define circ-row� (beside circ-unit circ-unit� circ-unit circ-unit))

(above circ-row circ-row � circ-row circ-row)

22 of 39

Your client called

Now they want a grid of grids of circles rather than squares

23 of 39

What’s wrong with this?

  • Defining unit and row saves us a little bit of work, but …
  • What we really want to do is to name the pattern of making a grids of shapes…
  • We need more abstraction

24 of 39

What we want to be able to say

(grid (circle 25 "outline" "black"))

25 of 39

What kind of a thing is grid?

  • Well, it takes inputs
  • It returns an output
  • It must be a function!!!

  • In fact, we even know what it should do
    • It should make a row from its input
    • Then make a stack of the rows
    • And return it back to us

26 of 39

lambda expressions

27 of 39

Compound functions

(lambda (name1 name2namen) output-expression)

(λ (name1 name2namen) output-expression)

Remember, functions are just another data object!

You can construct new functions from old code using λ expressions

    • name1 name2namen are names to give to the inputs of the function when it’s called
    • output-expression is an expression to compute the output of the function

Note: you type the λ symbol by typing command-\ on Macs or control-\ on Windows

28 of 39

Compound functions

(lambda (name1 name2namen) output-expression)

(λ (name1 name2namen) output-expression)

Remember, functions are just another data object!

When called, the function

  • Substitutes its inputs for name1 name2namen in output-expression
  • Computes the value of the resulting expression
  • Returns it

29 of 39

Compound functions

(lambda (name1 name2namen) output-expression)

(λ (name1 name2namen) output-expression)

If you call (λ (x) (+ x 1)) with an input of 2

  • It take the output expression, (+ x 1)
  • Substitutes 2 in for x to get (+ 2 1)
  • And runs it to get 3
  • 3 is the output of the call

So ((λ (x) (+ x 1)) 2) is a function call

  • The function is (λ (x) (+ x 1))
  • The input is 2
  • It simplifies it to (+ 2 1)
  • And outputs 3

30 of 39

Defining grid

(define row� (λ (unit)� (beside unit unit unit unit)))

(define stack� (λ (unit)� (above unit unit unit unit)))

(define grid�(λ (unit)� (stack (row unit))))

31 of 39

Using / Running grid

(define row� (λ (unit)� (beside unit unit unit unit)))

(define stack� (λ (unit)� (above unit unit unit unit)))

(define grid�(λ (unit)� (stack (row unit))))

(grid (circle 25 "solid" "blue"))

32 of 39

Using / Running grid

(define row� (λ (unit)� (beside unit unit unit unit)))

(define stack� (λ (unit)� (above unit unit unit unit)))

(define grid�(λ (unit)� (stack (row unit))))

(grid (circle 25 "solid" "blue"))

33 of 39

notating�type signatures

34 of 39

Type signatures

  • It’s important to keep track of what types of inputs and outputs are required by each function
    • We call this a function's type signature
  • You should always think about the type signature of a function when you use it
    • And whether the types of the inputs match up

35 of 39

Code comments

  • Racket ignores anything after a semicolon (;) in your code
    • Up to the end of the line
  • These are known as comments
    • Nearly all programming languages have them
    • You can use that as a way of writing notes to yourself in the code

36 of 39

Notating type signatures in code

  • It’s good practice when writing functions to notate their type signatures
  • We do that in Racket by using an ->

function name: input types … -> output type

square: number string color -> image

37 of 39

Notating type signatures in code

  • So we’re going to notate that grid, row, and stack expect images as inputs and produce images as outputs:

grid: image -> image

row: image -> image

stack: image -> image

38 of 39

Signature and purpose

; grid: image -> image�; Make a grid of identical pictures

(define grid� (λ (unit)� (stack (row unit))))

  • In this class, when you write a function, you should always start with a comment:
    • Noting its type signature
    • And a short purpose statement: what does the function do?
  • This helps you clarify your thinking about what you’re trying to write
  • If you can’t write these, then you aren’t ready to write the function!

39 of 39

Defining grid

; grid: image -> image�; Make a grid of identical pictures

(define grid�(λ (unit)� (stack (row unit))))

; row: image -> image�; Make a row of identical pictures

(define row� (λ (unit)� (beside unit unit unit unit)))

; stack: image-> image�; Make a stack of identical pictures

(define stack� (λ (unit)� (above unit unit unit unit)))