Transcript of Data Science: Advanced-R Boot Camp Functions (a.k.a. closures)
Data Science: Advanced-R Boot Camp Functions (a.k.a.
closures)(a.k.a. closures)
22 February 202022 February 202022 February 202022 February 202022
February 202022 February 202022 February 202022 February 202022
February 202022 February 202022 February 202022 February 202022
February 202022 February 202022 February 202022 February 202022
February 202022 February 202022 February 202022 February 202022
February 2020
1/21
2/21
Intro. Parts of a function Forms Scoping Lazy evaluations Exiting
Hands on Q & A Conclusion References Files
Table of contents (1 of 1)
1 Intro.
3 Forms
4 Scoping
c©Old Dominion University
3/21
Intro. Parts of a function Forms Scoping Lazy evaluations Exiting
Hands on Q & A Conclusion References Files
What are we going to cover?
We’re going to talk about:
Functions in all their glory
Their different forms
What can do they do when they are finished
c©Old Dominion University
4/21
Intro. Parts of a function Forms Scoping Lazy evaluations Exiting
Hands on Q & A Conclusion References Files
A definition
The central computation in R is a function call, de- fined by the
function object itself and the objects that are supplied as the
arguments. In the functional programming model, the result is
defined by another object, the value of the call.
J. Chambers [1]
Sometimes rephrased as: “To understand computations in R, two
slogans are helpful:
Everything that exists is an object.
Everything that happens is a function call.”
– John Chambers
5/21
Intro. Parts of a function Forms Scoping Lazy evaluations Exiting
Hands on Q & A Conclusion References Files
Each part of a function is visible (usually):
formals: (a.k.a the argument list)
body: the “code” inside a function
environment: the internal data structure that associates names and
values
simple <- function(a, b, c=3)
{ returnValue <- c*(a+b)
6/21
Intro. Parts of a function Forms Scoping Lazy evaluations Exiting
Hands on Q & A Conclusion References Files
Primitive functions are “secretive”:
body is not visible
formals(list)
body(list)
environment(list)
attributes(list)
attr(list,"srcref")
typeof(list)
7/21
Intro. Parts of a function Forms Scoping Lazy evaluations Exiting
Hands on Q & A Conclusion References Files
There are different ways to call/invoke a function[4]
Some are obvious, others not.
prefix: the name of the function comes before the arguments
infix: the name of the function comes between its arguments
replacement: seem to modify their arguments in place, and have the
special name xxx<-.
special: misc. language features that can also be written as
prefix
## prefix
8/21
Intro. Parts of a function Forms Scoping Lazy evaluations Exiting
Hands on Q & A Conclusion References Files
Prefix notation
The function name comes before its arguments. These constitute the
majority of function calls in R.
## prefix
9/21
Intro. Parts of a function Forms Scoping Lazy evaluations Exiting
Hands on Q & A Conclusion References Files
Infix notation
The function names come between its arguments. Infix forms are used
for many mathematical operators, and for user-defined function that
begin and end with the % character.
## infix
10/21
Intro. Parts of a function Forms Scoping Lazy evaluations Exiting
Hands on Q & A Conclusion References Files
Replacement functions
Replacement functions act like they modify their arguments in
place, and have the special name xxx<-. They typically have two
arguments (x and value), although they can have more, and they must
return the modified object.
## replacement
11/21
Intro. Parts of a function Forms Scoping Lazy evaluations Exiting
Hands on Q & A Conclusion References Files
Special functions
“Finally, there are a bunch of language features that are usually
written in special ways, but also have prefix forms.”
H. Wickham [4]
(x) (’(’(x)) # where x <- function(x){x}
{x} (’{’(x)) # where x <- function(x){x}
x[[i]] (’[[’(x, i))
if (cond) TRUE else FALSE (’if’(cond, TRUE, FALSE)) # if cond <-
TRUE
repeat expr (’repeat’(expr))
12/21
Intro. Parts of a function Forms Scoping Lazy evaluations Exiting
Hands on Q & A Conclusion References Files
Where do I look to find things?
There are specific rules, and order:
1 Name masking: names defined inside a function mask names defined
outside a function.
2 Functions vs. variables: functions and variables are treated the
same.
3 Fresh start: normally functions have no memory, so all searches
act the same
4 Dynamic lookup: lexical scoping determines where, but not when to
look for values. R looks for values when the function is run, not
when the function is created.
x <- 10
levelOne <- function(){
print(x)
levelOne()
levelTwo()
R only looks one level up, then globally. c©Old Dominion
University
13/21
Intro. Parts of a function Forms Scoping Lazy evaluations Exiting
Hands on Q & A Conclusion References Files
R only uses things when it needs to
Function arguments are only evaluated if accessed (lazily).
1 Promise: consists of: (1) an expression, (2) an environment, and
(3) a computed value.
2 Defaults: can be defined in terms of other arguments, or even in
terms of variables defined later in the function:
3 Missing: To determine if an arguments value comes from the user
or from a default, you can use missing()
y <- 10
h02 <- function(x) {
y <- 100
x + 1
14/21
Intro. Parts of a function Forms Scoping Lazy evaluations Exiting
Hands on Q & A Conclusion References Files
Default arguments
Default doesn’t mean the same thing all the time.
The evaluation environment is slightly different for default and
user supplied arguments, as default arguments are evaluated inside
the function. This means that seemingly identical calls can yield
different results.
h04 <- function(x = 1,
y = x * 2,
z = a + b) {
h05()
h05(ls())
You need to be thoughtful when using defaults. c©Old Dominion
University
15/21
Intro. Parts of a function Forms Scoping Lazy evaluations Exiting
Hands on Q & A Conclusion References Files
Giving back to the user
Once you are in a function, how do you get out?
Implicitly or explicitly: either the last value computed, or via
the return() function
Visible or invisible: during interactive use, return values are
visible or not
Errors: error indicates that something has gone wrong, and forces
the user to deal with the problem.
Exit handlers: identifying single, or multiple expressions to be
executed when the function exits
implicit <- function()
16/21
Intro. Parts of a function Forms Scoping Lazy evaluations Exiting
Hands on Q & A Conclusion References Files
Exit handlers
Making sure things happen, regardless of what the function does.
Sometimes a function needs to make temporary changes to the global
state. To ensure that these changes are undone and that the global
state is restored no matter how a function exits, use on.exit() to
set up an exit handler.
Custom error handlers are beyond the scope of this bootcamp.
silly <- function(x) {
17/21
Intro. Parts of a function Forms Scoping Lazy evaluations Exiting
Hands on Q & A Conclusion References Files
Create an “evil” function
1 Replace the current definition of the special operator: “(“
2 If the input argument is numeric increase it by 1, approximately
5% of the time.
3 Keep track of how often the function is called.
Be sure to delete the evil definition of the operator.
c©Old Dominion University
18/21
Intro. Parts of a function Forms Scoping Lazy evaluations Exiting
Hands on Q & A Conclusion References Files
Q & A time.
Q: Why was Stonehenge abandoned? A: It wasn’t IBM compatible.
c©Old Dominion University
19/21
Intro. Parts of a function Forms Scoping Lazy evaluations Exiting
Hands on Q & A Conclusion References Files
What have we covered?
Functions are first class objects Functions are composed of three
parts:
formals (a.k.a the argument list) body the “code” inside a function
environment the internal data structure that associates names and
values
Functions come in different “flavors” Functions can be called in
different ways
Next: Looking at environments
c©Old Dominion University
20/21
Intro. Parts of a function Forms Scoping Lazy evaluations Exiting
Hands on Q & A Conclusion References Files
References (1 of 1)
[1] John Chambers, Software for data analysis: programming with r,
Springer Science & Business Media, 2008.
[2] DataMentor Staff, R infix operator, https:
//www.datamentor.io/r-programming/infix-operator/, 2019.
[3] Joshua Ulrich, How can i view the source code for a function?,
https://stackoverflow.com/questions/19226816/how-
can-i-view-the-source-code-for-a-function, 2017.
c©Old Dominion University
Files of interest
1 Code snippets
## First codes simple <- function(a, b, c=3) { returnValue <-
c*(a+b) return(returnValue) } formals(simple) body(simple)
environment(simple) attributes(simple) attr(simple,"srcref")
typeof(simple) ## Second codes formals(list) body(list)
environment(list) attributes(list) attr(list,"srcref") typeof(list)
## Third codes x <- 3 y <- 4 '+'(x, y) x + y x <- 1:10
'second<-'<- function(x, value) { x[2] <- value x }
second(x) <- 5L x ## Third codes rm(list=ls()) x <- 10
levelOne <- function() { print(sprintf("%s %.0f",
as.character(match.call()[[1]]), x)) } levelTwo <- function() {
x <- 23 print(sprintf("%s %.0f",
as.character(match.call()[[1]]), x)) levelOne() }
print(sprintf("Global value of x is:%.0f", x)) levelOne()
levelTwo() ## Fourth codes rm(list=ls()) embedded <- function()
{ print(sprintf("Global %s()", as.character(match.call()[[1]]))) }
levelOne <- function() { embedded <- function() {
print(sprintf("Embedded %s()", as.character(match.call()[[1]]))) }
embedded() levelTwo() } levelTwo <- function() { embedded() }
embedded() levelOne() levelTwo() y <- 10 h02 <- function(x) {
y <- 100 x + 1 } h02(y) h02(y <- 1000) y h04 <- function(x
= 1, y = x * 2, z = a + b) { a <- 10 b <- 100 c(x, y, z) }
h04() h05 <- function(x = ls()) { a <- 1 ; x } h05()
h05(ls()) silly <- function(x) { on.exit(message("The first
one."), add = TRUE) on.exit(message("The second one."), add = TRUE)
if (x > 0){ stop("x < 0") } print(x) return (x) } silly(-1)
silly( 1)
"Chuck Cartledge"