class: title-slide, middle, inverse .leftcol30[ <center> <img src="https://github.com/emse-p4a-gwu/emse-p4a-gwu.github.io/raw/master/images/p4a_hex_sticker.png" width=250> </center> ] .rightcol70[ # Week 3: .fancy[Creating Functions] ### EMSE 4574: Intro to Programming for Analytics ### John Paul Helveston ### September 15, 2020 ] --- class: inverse # Quiz 2 # Go to `#classroom` channel in Slack for link
06
:
00
--- ### Thanks for the cute animals: ### Olivia Z., Kyara M., Eliese O., Helena R., David R., Carolyne I., Omar A. <style> * { box-sizing: border-box; } .column { float: left; width: 16.66%; padding: 5px; } /* Clearfix (clear floats) */ .row::after { content: ""; clear: both; display: table; } </style> <div class="row"> <div class="column"> <img src="images/animals/olivia_z.JPG" alt="Snow" style="width:100%"> </div> <div class="column"> <img src="images/animals/kyara_m.jpg" alt="Forest" style="width:100%"> </div> <div class="column"> <img src="images/animals/eliese_o.gif" alt="Mountains" style="width:100%"> </div> <div class="column"> <img src="images/animals/helena_r.jpg" alt="Mountains" style="width:100%"> </div> <div class="column"> <img src="images/animals/david_r.JPG" alt="Mountains" style="width:100%"> </div> <div class="column"> <img src="images/animals/carolyne_i.jpg" alt="Mountains" style="width:100%"> </div> </div> --- ...and [Alfie the alpaca](https://www.instagram.com/alfie_the_alpaca_in_adelaide/?hl=en): <img src="images/animals/omar_a.jpg" width="500px"> --- class: center # Video on? It's nice to see your faces :) .leftcol[ <center> <img src="images/zoom_video.jpg" width="500px"> </center> ] .rightcol[.left[ If you're okay with it, please turn on your camera - it creates a more engaging discussion environment and an opportunity for us to get to know each other better. Your privacy is important though, and I understand if you wish to keep it off. No pressure. ]] --- class: inverse, middle # Week 3: .fancy[Creating Functions] ## 1. Function syntax ## 2. Local vs global variables ## 3. Top-down design ## 4. Coding style --- class: inverse, middle # Week 3: .fancy[Creating Functions] ## 1. .orange[Function syntax] ## 2. Local vs global variables ## 3. Top-down design ## 4. Coding style --- # Basic function syntax .code90[ ```r functionName <- function(arguments) { # Do stuff here return(something) } ``` ] --- # Basic function syntax In English: > "`functionName` is a `function` of `arguments` that does..." .code90[ ```r functionName <- function(arguments) { # Do stuff here return(something) } ``` ] --- # Basic function syntax Example: > "`squareRoot` is a `function` of `n` that...returns the square root of `n`" .code90[ ```r squareRoot <- function(n) { return(n^0.5) } ``` ] -- .code90[ ```r squareRoot(64) ``` ``` ## [1] 8 ``` ] --- # `return()` and `cat()` statements -- .leftcol[.code90[ ```r isPositive <- function(n) { return(n > 0) } ``` ]] -- .rightcol[.code90[ ```r isPositive <- function(n) { cat(n > 0) } ``` ]] --- # `return()` and `cat()` statements .leftcol[.code90[ ```r isPositive <- function(n) { return(n > 0) } ``` `return()` _returns_ back a value ```r test <- isPositive(7) test ``` ``` TRUE ``` ]] .rightcol[.code90[ ```r isPositive <- function(n) { cat(n > 0) } ``` `cat()` _prints_ a value as a string ```r test <- isPositive(7) ``` ``` TRUE ``` ```r test ``` ``` Error: object 'test' not found ``` ]] --- ## `cat()` is short for "concatenating" -- ```r print_x <- function(x) { cat("The value of x is", x) } ``` -- ```r print_x(7) ``` ``` ## The value of x is 7 ``` -- ```r print_x_squared <- function(x) { cat("The value of x is", x, "and the value of x^2 is", x^2) } ``` -- ```r print_x_squared(7) ``` ``` ## The value of x is 7 and the value of x^2 is 49 ``` --- ## `cat()` adds a space between values by default -- ```r print_x <- function(x) { cat("The value of x is", x) } ``` -- ```r print_x(7) ``` ``` ## The value of x is 7 ``` -- Modify separator with the `sep` argument: ```r print_x <- function(x) { cat("The value of x is", x, sep = ": ") } ``` -- ```r print_x(7) ``` ``` ## The value of x is: 7 ``` --- class: inverse
02
:
00
# Code tracing practice .leftcol[.code80[ Consider these functions: ```r f1 <- function(x) { return(x^3) } f2 <- function(x) { cat(x^3) } f3 <- function(x) { cat(x^3) return(x^4) } f4 <- function(x) { return(x^3) cat(x^4) } ``` ]] .rightcol[.code80[ What will these lines of code produce? Write your answer down first, _then_ run the code to check. ```r f1(2) f2(2) f3(2) f4(2) ``` ]] --- class: inverse, middle # Week 3: .fancy[Creating Functions] ## 1. Function syntax ## 2. .orange[Local vs global variables] ## 3. Top-down design ## 4. Coding style --- # Local objects ### All objects inside function are **"local"** - they don't exist in the _global_ environment -- .leftcol[.code90[ ### Example: ```r squareOfX <- function(x) { * y <- x^2 # y here is "local" return(y) } ``` ]] -- .rightcol[ ```r squareOfX(3) ``` ``` ## [1] 9 ``` If you try to call `y`, you'll get an error: ```r y ``` ``` Error: object 'y' not found ``` ] --- # Global objects ### **Global** objects exist in the main environment. -- ### **NEVER, NEVER, NEVER** call global objects inside functions. -- .leftcol[ ```r print_x <- function(x) { cat(x) * cat(n) # n is global! } n <- 5 # Define n in the *global* environment print_x(5) ``` ``` ## 55 ``` ] -- .rightcol[ ```r n <- 6 print_x(5) ``` ``` ## 56 ``` Function behavior shouldn't change with the same arguments! ] --- # Global objects ### All objects inside functions should be **arguments** to that function -- .leftcol[ ```r print_x <- function(x, n = NULL) { cat(x) * cat(n) # n is local! } n <- 5 # Define n in the *global* environment print_x(5) ``` ``` ## 5 ``` ] -- .rightcol[ ```r n <- 6 print_x(5) ``` ``` ## 5 ``` Use `n` as argument: ```r print_x(5, n) ``` ``` ## 56 ``` ] --- class: inverse
02
:
00
## Code tracing practice .leftcol[.code70[ Consider this code: ```r x <- 7 y <- NULL f1 <- function(x) { cat(x^3) cat(y, x) } f2 <- function(x, y = 7) { cat(x^3, y) } f3 <- function(x, y) { cat(x^3) cat(y) } f4 <- function(x) { return(x^3) cat(x^4) } ``` ]] .rightcol[.code70[ What will these lines of code produce? Write your answer down first, _then_ run the code to check. ```r f1(2) f2(2) f3(2) f4(2) ``` ]] --- class: inverse, center # .fancy[Break]
05
:
00
--- class: inverse, middle # Week 3: .fancy[Creating Functions] ## 1. Function syntax ## 2. Local vs global variables ## 3. .orange[Top-down design] ## 4. Coding style --- # "Top Down" design <br> -- ## 1. Break the problem into pieces -- ## 2. Solve the "highest level" problem first -- ## 3. Then solve the smaller pieces --- .leftcol40[ **Example**: Given values `a` and `b`, find the value `c` such that the triangle formed by lines of length `a`, `b`, and `c` is a right triangle (in short, find hypotenuse) <br> .noborder[<img src="images/right-triangle-hypotenuse.png" width="250">] <br> ] --- .leftcol40[ **Example**: Given values `a` and `b`, find the value `c` such that the triangle formed by lines of length `a`, `b`, and `c` is a right triangle (in short, find hypotenuse) <br> .noborder[<img src="images/right-triangle-hypotenuse.png" width="250">] ] .rightcol55[ ### Hypotenuse: `\(c = \sqrt{a^2 + b^2}\)` ### Break the problem into two pieces: ### `\(c = \sqrt{x}\)` ### `\(x = a^2 + b^2\)` ] --- .leftcol40[ **Example**: Given values `a` and `b`, find the value `c` such that the triangle formed by lines of length `a`, `b`, and `c` is a right triangle (in short, find hypotenuse) <br> .noborder[<img src="images/right-triangle-hypotenuse.png" width="250">] ] .rightcol55[ ### Hypotenuse: `\(c = \sqrt{a^2 + b^2}\)` ### Break the problem into two pieces: ### `\(c = \sqrt{x}\)` ```r hypotenuse <- function(a, b) { return(sqrt(sumOfSquares(a, b))) } ``` ### `\(x = a^b + b^2\)` ```r sumOfSquares <- function(a, b) { return(a^2 + b^2) } ``` ] --- class: inverse
10
:
00
# Think-Pair-Share Create a function, `isRightTriangle(a, b, c)` that returns `TRUE` if the triangle formed by the lines of length `a`, `b`, and `c` is a right triangle and `FALSE` otherwise. Use the `hypotenuse(a, b)` function in your solution. **Hint**: you may not know which value (`a`, `b`, or `c`) is the hypotenuse. .leftcol[.code80[ ```r hypotenuse <- function(a, b) { return(sqrt(sumOfSquares(a, b))) } ``` ```r sumOfSquares <- function(a, b) { return(a^2 + b^2) } ``` ]] --- class: inverse, middle .leftcol60[ # Week 3: .fancy[Creating Functions] ## 1. Function syntax ## 2. Local vs global variables ## 3. Top-down design ## 4. .orange[Coding style] ] .rightcol40[ <img src="images/code_style.jpg" width="370px"> ] --- # Style matters! -- ## Which is easier to read? .leftcol60[.code80[ V1: ```r sumofsquares<-function(a,b)return(a^2 + b^2) ``` V2: ```r sum_of_squares <- function(a, b) { return(a^2 + b^2) } ``` ]] --- # Style matters! ## Which is easier to read? .leftcol60[.code80[ V1: ```r sumofsquares<-function(a,b)return(a^2 + b^2) ``` V2: <- **This one is _much_ better!** ```r sum_of_squares <- function(a, b) { return(a^2 + b^2) } ``` ]] --- # Use the "Advanced R" style guide: ## http://adv-r.had.co.nz/Style.html <br> -- ## Other good style tips on [this blog post](https://www.r-bloggers.com/%F0%9F%96%8A-r-coding-style-guide/) --- # Style guide: **Objects** .leftcol[ <img src="images/assignment.jpg" width="500px"> ] -- .rightcol[ - Use ` <- ` for assignment, not ` = ` - Put spacing around operators<br>(e.g. `x <- 1`, not `x<-1`) - Use [meaningful variable names](https://p4a.seas.gwu.edu/2020-Fall/L1.2-getting-started.html#Use_meaningful_variable_names) - This applies to file names too<br>(e.g. "`hw1.R`" vs. "`untitled.R`") ] --- # Style guide: **Functions** Generally, function names should be verbs: ```r add() # Good addition() # Bad ``` -- Avoid using the "`.`" symbol: ```r get_hypotenuse() # Good get.hypotenuse() # Bad ``` -- Use curly braces, with indented code inside: ```r sum_of_squares <- function(a, b) { return(a^2 + b^2) } ``` --- class: center .leftcol[ ## Indent by 4 spaces <center> <img src="images/indent.png" width="550px"> </center> ] .rightcol[ ## Set line length to 80 <center> <img src="images/length.png" width="550px"> </center> ] --- class: inverse
15
:
00
# Think-Pair-Share .leftcol[ `onesDigit(x)`: Write a function that takes an integer and returns its ones digit. Tests: - onesDigit(123) == 3 - onesDigit(7890) == 0 - onesDigit(6) == 6 - onesDigit(-54) == 4 ] .rightcol[ `tensDigit(x)`: Write a function that takes an integer and returns its tens digit. Tests: - tensDigit(456) == 5 - tensDigit(23) == 2 - tensDigit(1) == 0 - tensDigit(-7890) == 9 ] --- class: inverse ### Hint #1: You may want to use `onesDigit(x)` as a helper function for `tensDigit(x)` ### Hint #2: .leftcol[ The mod operator (`%%`) "chops" a number and returns everything to the _right_ ```r 123456 %% 1 ``` ``` ## [1] 0 ``` ```r 123456 %% 10 ``` ``` ## [1] 6 ``` ] .rightcol[ The integer divide operator (`%/%`) "chops" a number and returns everything to the _left_ ```r 123456 %/% 1 ``` ``` ## [1] 123456 ``` ```r 123456 %/% 10 ``` ``` ## [1] 12345 ``` ] --- class: inverse
15
:
00
## Think-Pair-Share .leftcol[ `eggCartons(eggs)`: Write a function that reads in a non-negative number of eggs and prints the number of egg cartons required to hold that many eggs. Each egg carton holds one dozen eggs, and you cannot buy fractional egg cartons. - eggCartons(0) == 0 - eggCartons(1) == 1 - eggCartons(12) == 1 - eggCartons(25) == 3 ] .rightcol[ `militaryTimeToStandardTime(n)`: Write a function that takes an integer between 0 and 23 (representing the hour in [military time](http://militarytimechart.com/)), and returns the same hour in standard time. - militaryTimeToStandardTime(0) == 12 - militaryTimeToStandardTime(3) == 3 - militaryTimeToStandardTime(12) == 12 - militaryTimeToStandardTime(13) == 1 - militaryTimeToStandardTime(23) == 11 ] --- # [HW 3](https://p4a.seas.gwu.edu/2020-Fall/hw3-creating-functions.html) -- - ### Use the template -- - ### Use Polya's problem solving technique: 1. Understand the problem 2. Devise a plan 3. Carry out the plan 4. Check your work -- - ### Try out the autograder (Saurav will DM you your password on Slack)