Unit 2 R Factorial Functions
Unit 2 R Factorial Functions
R Functions
func_name <- function (argument)
{
statement
}
Example of a Function
pow <- function(x, y)
{
result <- x^y
print(paste(x,"raised to the power", y, "is", result))
}
How to call a function?
We can call the above function as follows.
>pow(8, 2)
[1] "8 raised to the power 2 is 64"
Named Arguments
pow(x = 8, y = 2)
[1] "8 raised to the power 2 is 64"
pow(y = 2, x = 8)
[1] "8 raised to the power 2 is 64"
pow(x=8, 2)
[1] "8 raised to the power 2 is 64"
pow(2, x=8)
[1] "8 raised to the power 2 is 64"
Default Values for Arguments
pow <- function(x, y = 2)
{
result <- x^y
print(paste(x,"raised to the power", y, "is", result))
}
pow(3)
[1] "3 raised to the power 2 is 9"
pow(3,1)
[1] "3 raised to the power 1 is 3"
R Return Value from Function
return(expression)
Example: return()
check <- function(x)
{
if (x > 0)
{
result <- "Positive"
}
else if (x < 0) { result <- "Negative"
}
else
{
result <- "Zero"
}
return(result)
}
> check(1)
[1] "Positive"
> check(-10)
[1] "Negative"
> check(0)
[1] "Zero"
Multiple Returns
multi_return <- function()
{
my_list <- list("color" = "red", "size" = 20, "shape" = "round") return(my_list)
}
a <- multi_return()
a$color
[1] "red"
a$size
[1] 20
a$shape
[1] "round"
Lazy Evaluation of Function
Arguments to functions are evaluated lazily, which means so they are evaluated only
when needed by the function body.
# Create a function with arguments.
new.function <- function(a, b)
{
print(a^2)
print(a)
print(b)
}
# Evaluate the function without supplying one of the arguments.
new.function(6)
When we execute the above code, it produces the following result:
[1] 36
[1] 6
Error in print(b) : argument "b" is missing, with no default
R Recursive Function
recursive.factorial <- function(x)
{
if (x == 0)
return (1)
else
return (x * recursive.factorial(x-1))
}
> recursive.factorial(0)
[1] 1
> recursive.factorial(5)
[1] 120
Scoping Rules
The scoping rules of a language determine how a value is associated with a free
variable in a function.
R uses lexical scoping or static scoping.
Lexical scoping means that the values of free variables are searched for in the
environment in which the function was defined.
An alternative to lexical scoping is dynamic scoping.
Why Lexical Scoping?
Lexical Scoping is a set of rules that helps to determine how R represents the value
of a symbol.
It is an in-built rule in R which automatically works at the language level.
Consider the following example:
f <- function(x, y)
{
x*y*z
}
In this:
x and y are formal arguments
z as the free variable
Therefore, the scoping rules of the language determine how values are assigned to
free variables. Free variables are not formal arguments and not local variables that are
assigned inside of the function body.
Name Masking
The following example illustrates the most basic principle of lexical scoping, and you
should have no problem predicting the output.
If variable is not defined inside the function:
Example:
c <- 10
f <- function(a, b)
{
a+b+c
}
f(8, 5)
Output:
[1] 23
It takes the c value as 10 and then adds these numbers and finally we are
having 23 as output.
If name is not defined inside the function:
If a name isn’t defined inside a function, R will look one level up.
Example:
a <- 10
b <- function()
{
c <- 11
c(a, c)
}
b()
Output:
[1] 10 11
Functions vs Variables
The same principles apply regardless of the type of associated value — finding
functions works exactly the same way as finding variables:
Example:
a <- function(x) 10 * x
b <- function(){
a <- function(x) x + 10
a(12)
}
b()
Output:
[1] 22
A Fresh Start
When a function is called, a new environment is created every time. Each
acknowledgement is completely independent because a function cannot tell what
happened when it was run last time.
Example:
a <- function(){
if(!exists("z"))
{
z <- 10
}
else
{
z <- z+10
}
z
}
a()
Output:
[1] 10
Dynamic Lookup
Lexical scoping controls where to look for values not when to look for them. R looks for
the values when the function is executed not when it is created. The output of the
function can be different depending on objects outside its environment.
Example:
g <- function() x^3
x <- 10
g()
Output:
[1] 1000
There is a function in R which is findGlobals() from codetools and it helps us to find all
global variables being used in a function and lists all the external dependencies of a
function. findGlobals() find the global variables and functions which are used by the
closure.
Example:
aGlobal <- rnorm(10)
bGlobal <- rnorm(10)
f <- function()
{
a <- aGlobal
b <- bGlobal
plot(b ~ a)
}
codetools::findGlobals(f)
Output:
[1] "{" "~" "<-" "aGlobal" "bGlobal" "plot"
We can manually change the environment to the empty
environment emptyenv(). emptyenv() is a totally empty environment.