When providing a default argument to an R function, this argument is evaluated when first used in the function. How is it possible to evaluate default argument earlier in an elegant way? Example:
f <- function(x, y = 2 * x)
{
if(x < 0) x = 10
y
}
f(1) ## Returns 2
f(-1) ## Returns 20 but I would like it to return -2
Thanks
The answer wasn't to hard to find. The function 'force' does the trick:
f <- function(x, y = 2 * x)
{
force(y)
if(x < 0) x = 10
y
}
f(1) ## Returns 2
f(-1) ## -2
Related
Suppose I have a function with a kink. I want to derive a kink point, which in this case is 0.314. I tried optim but it does not work.
Here is an example. In general, I want to derive c. Of course, I could use brute force, but it is slow.
# function with a kink
f <- function(x, c){
(x >= 0 & x < c) * 0 + (x >= c & x <=1) * (sin(3*(x-c))) +
(x < 0 | x > 1) * 100
}
# plot
x_vec <- seq(0, 1, .01)
plot(x_vec, f(x_vec, c = pi/10), "l")
# does not work
optim(.4, f, c = pi/10)
This function has no unique minimum.
Here, a trick is to transform this function a little bit, so that its kink becomes a unique minimum.
g <- function (x, c) f(x, c) - x
x_vec <- seq(0, 1, 0.01)
plot(x_vec, g(x_vec, c = pi/10), type = "l")
# now works
optim(0.4, g, c = pi/10, method = "BFGS")
#$par
#[1] 0.3140978
#
#$value
#[1] -0.3140978
#
#$counts
#function gradient
# 34 5
#
#$convergence
#[1] 0
#
#$message
#NULL
Note:
In mathematics, if we want to find something, we have to first define it precisely. So what is a "kink" exactly? In this example, you refer to the parameter c = pi / 10. But what is it in general? Without a clear definition, there is no algorithm/function to get it.
I fear I get something really wrong. The basics are from here
and a basic (minimal) example is understood (I think) and working:
fun.default <- function(x) { # you could add further fun.class1 (works)...
print("default")
return(x[1] + x[2])
}
my_fun <- function(x) {
print("my_fun")
print(x)
res <- UseMethod("fun", x)
print(res)
print("END my_fun...")
return(res)
}
x <- c(1, 2)
my_fun(x)
However, if I want to add parameters, something goes really wrong. Form the link above:
Once UseMethod has found the correct method, it’s invoked in a special
way. Rather than creating a new evaluation environment, it uses the
environment of the current function call (the call to the generic), so
any assignments or evaluations that were made before the call to
UseMethod will be accessible to the method.
I tried all variants I could think of:
my_fun_wrong1 <- function(x, y) {
print("my_fun_wrong1")
print(x)
x <- x + y
print(x)
res <- UseMethod("fun", x)
print(res)
print("END my_fun_wrong1...")
return(res)
}
x <- c(1, 2)
# Throws: Error in fun.default(x, y = 2) : unused argument (y = 2)
my_fun_wrong1(x, y = 2)
my_fun_wrong2 <- function(x) {
print("my_fun_wrong2")
print(x)
x <- x + y
print(x)
res <- UseMethod("fun", x)
print(res)
print("END my_fun_wrong2...")
return(res)
}
x <- c(1, 2)
y = 2
# Does not throw an error, but does not give my expetced result "7":
my_fun_wrong2(x) # wrong result!?
rm(y)
my_fun_wrong3 <- function(x, ...) {
print("my_fun_wrong3")
print(x)
x <- x + y
print(x)
res <- UseMethod("fun", x)
print(res)
print("END my_fun_wrong3...")
return(res)
}
x <- c(1, 2)
# Throws: Error in my_fun_wrong3(x, y = 2) : object 'y' not found
my_fun_wrong3(x, y = 2)
Edit after answer G. Grothendieck: Using fun.default <- function(x, ...) I get
Runs after change, but I don't understand the result:
my_fun_wrong1(x, y = 2)
[1] "my_fun_wrong1"
[1] 1 2
[1] 3 4 # Ok
[1] "default"
[1] 3 # I excpect 7
As before - I don't understand the result:
my_fun_wrong2(x) # wrong result!?
[1] "my_fun_wrong2"
[1] 1 2
[1] 3 4 # Ok!
[1] "default"
[1] 3 # 3 + 4 = 7?
Still throws an error:
my_fun_wrong3(x, y = 2)
[1] "my_fun_wrong3"
[1] 1 2
Error in my_fun_wrong3(x, y = 2) : object 'y' not found
I think, this question is really useful!
fun.default needs ... so that the extra argument is matched.
fun.default <- function(x, ...) {
print("default")
return(x[1] + x[2])
}
x <- c(1, 2)
my_fun_wrong1(x, y = 2)
## [1] "my_fun_wrong1"
## [1] 1 2
## [1] 5 6
## [1] 3
Also, any statements after the call to UseMethod in the generic will not be evaluated as UseMethoddoes not return so it is pointless to put code after it in the generic.
Furthermore, you can't redefine the arguments to UseMethod. The arguments are passed on as they came in.
Suggest going over the help file ?UseMethod although admittedly it can be difficult to read.
Regarding the quote from ?UseMethod that was added to the question, this just means that the methods can access local variables defined in the function calling UseMethod. It does not mean that you can redefine arguments. Below ff.default refers to the a defined in ff.
a <- 0
ff <- function(x, ...) { a <- 1; UseMethod("ff") }
ff.default <- function(x, ...) a
ff(3)
## [1] 1
I have a function f(x) where the default value of x is 2. The function returns the square.
f <- function(x = 2){
return(x^2)
}
I want to check in the function if the user gives value to x. Even if the value given is 2, I want to know.
Perhaps this is the equivalent code of what I want.
f <- function(x){
if(!missing(x)) print("User did not give value to x")
if(missing(x)) x <- 2
return(x^2)
}
I want to do something similar by setting the default value of x to 2 (not NULL also). Is it possible?
You may use match.call. In this case we could do
f <- function(x = 2) {
if(is.null(match.call()$x))
print("Nothing")
x^2
}
f()
# [1] "Nothing"
# [1] 4
f(2)
# [1] 4
f(x = 2)
# [1] 4
How to interpret this function?
g <- function(x,y) y <= x^2
How to call the function? g(2) or g(2,3)? What will it return?
<= is a comparison operator, where you are comparing whether the Left-Hand Side (LHS) is less than or equal to the Rigth-Hand Side. The answer to which will be either TRUE or FALSE.
In your example, the function is returning the result of
2 <= 3^2
[1] TRUE
You will call the function like g(2,3), as both x and y are required.
g <- function(x,y) y <= x^2
g(2,3)
[1] TRUE
The arguments (x, y) are required because you haven't set any default values for them. To do this you define the values in the arguments of the function
g <- function(x = 2, y = 3) y <= x^2 ## assigned default values
g() ## using the default values
[1] TRUE
Having the function all on one line is a shorthand of the more explicit
g <- function(x, y){
return(y <= x^2)
}
g(2,3)
[1] TRUE
Does R have a concept of += (plus equals) or ++ (plus plus) as c++/c#/others do?
No, it doesn't, see: R Language Definition: Operators
Following #GregaKešpret you can make an infix operator:
`%+=%` = function(e1,e2) eval.parent(substitute(e1 <- e1 + e2))
x = 1
x %+=% 2 ; x
R doesn't have a concept of increment operator (as for example ++ in C). However, it is not difficult to implement one yourself, for example:
inc <- function(x)
{
eval.parent(substitute(x <- x + 1))
}
In that case you would call
x <- 10
inc(x)
However, it introduces function call overhead, so it's slower than typing x <- x + 1 yourself. If I'm not mistaken increment operator was introduced to make job for compiler easier, as it could convert the code to those machine language instructions directly.
R doesn't have these operations because (most) objects in R are immutable. They do not change. Typically, when it looks like you're modifying an object, you're actually modifying a copy.
Increment and decrement by 10.
require(Hmisc)
inc(x) <- 10
dec(x) <- 10
We released a package, roperators, to help with this kind of thing. You can read more about it here: https://happylittlescripts.blogspot.com/2018/09/make-your-r-code-nicer-with-roperators.html
install.packages('roperators')
require(roperators)
x <- 1:3
x %+=% 1; x
x %-=% 3; x
y <- c('a', 'b', 'c')
y %+=% 'text'; y
y %-=% 'text'; y
# etc
We can override +. If unary + is used and its argument is itself an unary + call, then increment the relevant object in the calling environment.
`+` <- function(e1,e2){
# if binary `+`, keep original behavior
if(!missing(e2)) return(base::`+`(e1, e2))
# if inner call isn't unary `+` called on language object,
# keep original behavior
inner_call <- substitute(e1)
inner_call_is_plus_on_lng <-
length(inner_call) == 2 &&
identical(inner_call[[1]], quote(`+`)) &&
is.language(inner_call[[2]])
if(!inner_call_is_plus_on_lng) return(base::`+`(e1))
eval.parent(substitute(X <- X + 1, list(X = inner_call[[2]])))
}
x <- 10
++x
x
#> [1] 11
other operations don't change :
x + 2
#> [1] 13
x ++ 2
#> [1] 13
+x
#> [1] 11
x
#> [1] 11
I can't really recommend it since you're messing with primitives which are optimised for a reason.
We can also use inplace
library(inplace)
x <- 1
x %+<-% 2
If you want to use i++ in an array to increment the index, you can try i <- i + 1, for example,
k = 0
a = 1:4
for (i in 1:4)
cat(a[k <- k + 1], " ")
# 1 2 3 4
but here <- can NOT be replaced with =, which does not update the index,
k = 0
a = 1:4
for (i in 1:4)
cat(a[k = k + 1], " ")
# 1 1 1 1
since = and <- are not always equivalent, as said in ?`<-`