Wednesday, November 11, 2015

R Basics 9 - Writing Functions

Functions in R are called closures.
# Don't be deceived by the curly brackets;
# R is much more like Lisp than C or Java.
# Defining problems in the terms of function
# calls and their lazy, delayed evaluation
# (variable resolution) is R's big feature.

Standard form (for named functions)
plus <- function(x, y) {x+y}
plus(5,6)
# return() not needed - last value returned
# Optional curly brackets with 1-line fns:
x.to.y <- function(x,y) return (x^y)

Returning values
# return() - can use to aid readability and fro exit part way trhrough a function
# invisible() - return values thant do not print if not assigned.
# Traps: return() is a function, not a statement. The brackets are needed.

Anonymous fucntions
# Often used in arguments to fucntions:
v <- 1:9;
cube <- sapply(v, function(x) x^3)

Arguments are passed by value
# Effectively arguments are copied, and any changes made to the argument within the function do not affect the caller's copy.
# Trap: arguments are not typed and your function could be passed anything!
# Upfront argument checking advised!

Arguments passed by position or name
b <- function(cat, dog, cow) cat+dog+cow
b(1,2,3)
b(cow=3, cat =1, dog=2)
# Trap: not all arguments need to passed
f <- funciton(x) missing(x); f(); f('here')
# match.arg() - argument partial matching

Default arguments
# Default arguments can be specified 
x2y.1 <- function(x, y=2) {x^y}
x2y.2 <- function(x, y=x) {x^y}
x2y.2(3)
x2y.2(2,3)

The dots argument (...) is a catch - all
f <- function(...) {
# simle way to access dots arguments
dots <- list()
}
x <- f(5);
dput(x)
g <- function(...) {
dots <- substitute(list(,,,))[-1]
dots.names <- sapply(dots, deparse)
}

x <- g(a,b,c)
dput(x) -> c("a", "b", "c")
# dots can be passed to another function:
h <- function(x, ...) g(...)
x <- h(a, b, c);

Function environment
# When a function is called a new environment (frame) is created for it.
# There frames are found in the call stack. Fist frame is the global environment 
# Next Function reaches back into the call stack.
called.by <- function() {
# returns string 
if(length(sys.parents()) <=2) return('.GlobalEnv')
deparse(sys.call(sys.parent(2)))
}
g <- function(...) { called.by() }
f <- fucntion(...) g(...);
f(a,2)

Variable scope and unbound variables
# Within a function, variables are resoved in the local frame first, 
# then in terms of super-functions (when a functions defined inside a function), then in terms of the global environment.
h <- fucntion(x) { x+a }
a <- 5
h(5)
k <- function(x) { a<- 100; h(x) }
k(10)

Super assignment
# x <<- y ignores the local x, and looks up the super-environments for a x to replace 
accumulator <- fucntion() {
a <- 0
function(x) {
a <<- a +x
 }
}
acc <- accumulator()
acc(1)
acc(5)
acc(2)

Operator and replacement functions
`+`(4,5) # -> 9 
- operators are just fns
`%plus%` <- function(a,b) {a+b}
# "FUN(x) <- v is parsed as: x <- FUN(x, v)
"cap<-" <- function(x, value) 
ifelse(x>value, value, x)
x <- c(1,10,100);
cap(x) <- 9

Exeptions
tryCatch(print('pass'), error=fucntion(e) print('bad'), finally=print('done'))
tryCatch(stop('fail'), error=function(e) print('bad'), finally=print('done'))

Useful language reflection functions
exists(); 
get();
assign() - for variabels
substitute()
bquote()
eval()
do.call()
parse()
deparse()
quote()
enquote()

No comments:

Post a Comment

Blog Archive