To extend the usability of a R function, we need to pass an argument of type function (FUN), Could you please demonstrate how to declare a function parameter inside in another function and how to call it. Like
MyOperation <- function(x, y, FUN){
int sum <- x+y
if (!missing(FUN)) sum<-FUN(sum)}
return sum
}
Res <- MyOperation(x=1, y=2, FUN=function(n){...})
You don't declare variables in R. Also you can specify a default value right in the formal argument list. You don't need to use missing in this situation.
This runs FUN(x + y) or returns x+y if FUN is not specified.
myOp2 <- function(x, y, FUN = identity) FUN(x + y)
myOp2(1, 2)
## [1] 3
myOp2(1, 3, sqrt)
## [1] 2
One enhancement might be to allow the function to be specified either as a function or as a character string:
myOp2a <- function(x, y, FUN = identity) {
FUN <- match.fun(FUN)
FUN(x + y)
}
myOp2a(1, 3, "sqrt")
## [1] 2
myOp2a(1, 3, sqrt)
## [1] 2
This sums x and y if FUN is not specified; otherwise, it runs FUN with the arguments x and y.
myOp3 <- function(x, y, FUN = sum) FUN(x, y)
myOp3(1, 2)
## [1] 3
myOp3(1, 2, min)
## [1] 1
You just have some basic R syntax problems there. There's no int in R, your function closing bracket was in the wrong place, return() is a function in R -- not a keyword. Check out
MyOperation<-function(x,y,FUN){
sum <- x+y
if (!missing(FUN)) sum<-FUN(sum)
return(sum)
}
MyOperation(x=1,y=2)
# [1] 3
MyOperation(x=1,y=2,FUN=function(n){n+100})
# [1] 103
Related
f1<-function(x,y){
f2<-function(a,b){
print("f2")
return(a+b)}
f2(x,y)
print("f1")
return(x-y)}
f1(8,5)
I was trying above code to figure out the steps of operating function within function, so instead of writing two separate functions, I write the above code. But I can't get the output for a+b (which is 13)
[1] "f2"
[1] "f1"
[1] 3
#[1] 13, this output is missing.
How should the code be corrected? Thank you.
*additional question: when I only write x-y instead of return(x-y) at the last line of the function f1, I got the same output. Is simply write x-y a bad practice or accpetable?
-------------------------Update:
I just find out a way to get all the four outputs by changing the 4th line from return(a+b) to print(a+b)
or to make it more simple, only use the x,yarguments:
f1<-function(x,y) {
f2<-function() {
print("f2")
print(x+y)
}
f2()
print("f1")
x-y
}
while I still don't understand why using return(x+y) or simply x+y at the 4th line could not get the output of 13?
When an expression is on a line by itself it will automatically print if you do it at the R console but that does not happen if it is within a function or within an expression. Use cat or print for displaying.
To return two objects return a list containing both of them as shown at below.
The value of the last line that is run in a function is returned so you rarely need return.
f1a <- function(x, y) {
f2 <- function(a, b) {
print("f2")
a + b
}
print("f1")
list(x - y, f2(x, y))
}
result <- f1a(8, 5)
## [1] "f1"
## [1] "f2"
result[[1]]
## [1] 3
result[[2]]
## [1] 13
result
## [[1]]
## [1] 3
##
## [[2]]
## [1] 13
Other things we could do would be to replace the list(...) line in the code above with one of the following. (The c versions would only be used if we knew that the arguments were always scalars.)
list(f1 = x - y, f2 = f2(x, y)) # named list
c(x - y, f2(x, y)) # 2 element numeric vector
c(f1 = x - y, f2 = f2(x, y)) # 2 element named numeric vector
cbind(f1 = x - y, f2 = f2(x, y)) # matrix w column names
data.frame(f1 = x - y, f2 = f2(x, y)) # data.frame
Take the following code:
f2 <- function(...) {
print(list(...))
}
f1 <- function(x, y = 1, ...) {
z <- 20
f2(x, y, ...)
}
f1(5, k = 6)
If I change the arguments to f1, and I still want to pass all those arguments to f2, I would need to change the call to f2. Is it possible to write the call to f2 so that it does not name x and y explicitly? Something like the following (non-working code):
f1 <- function(x, y = 1, ...) {
z <- 20
do.call(f2, formals())
}
I can use environment(), but then I need to take care that I call it at the very beginning:
f1 <- function(x, y = 1, ...) {
argv <- c(as.list(environment()), ...)
z <- 20
do.call(f2, argv)
}
Is there maybe a simpler, more direct way?
It's not clear whether you wanted the variable z added to the call, but in either case you can achieve what you are looking for using match.call. You can simply swap in the quoted name of f2 as the first element in the matched call, and if you wish to add the missing defaults from the f1 formals, you can find them in formals() and write any missing ones into the matched call. Finally, you evaluate this call.
f1 <- function(x, y = 1, ...) {
mc <- match.call()
form <- names(formals())[!names(formals()) %in% names(mc)]
form <- form[form != "..."]
mc[[1]] <- quote(f2)
mc[form] <- formals()[form]
mc$z <- 20
eval(mc)
}
f2 <- function(...) {
print(list(...))
}
f1(5, k = 6)
#> $x
#> [1] 5
#>
#> $k
#> [1] 6
#>
#> $y
#> [1] 1
#>
#> $z
#> [1] 20
Created on 2020-09-29 by the reprex package (v0.3.0)
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
The title basically says it all.
I would like to pass a function to another argument, but I need to specify a parameter of the function that I use as input, e.g. here 0.5:
function1(function2(x, parameter = 0.5))
how do I do this in R ?
Here are some alternatives:
1) define anonymous function
# test data
fun2 <- function(x, y) x + y
fun1 <- function(fun, x) fun(x)
fun1(function(x) fun2(x, y = 2), 1)
## [1] 3
2) partial in purrr package
library(purrr)
fun1(partial(fun2, y = 2), 1)
## [1] 3
3) Curry in functional package
library(functional)
fun1(Curry(fun2, y = 2), 1)
## [1] 3
4) %<% in curry package
This package defines a %<% operator to do currying:
library(curry)
library(magrittr)
fun2 %<% 2 %>% fun1(1)
## [1] 3
5) default package This package lets one set arguments of a function to a default.
library(default)
default(fun2) <- list(y = 2)
fun1(fun2, 1)
## [1] 3
fun2 <- reset_default(fun2)
6) dots In certain cases the function to which another function is passed has a ... argument which can supply arguments to the passed function. For example, here we pass a=1 to obj via the dots argument of optimize.
obj <- function(x, a) (x - a)^2
optimize(obj, c(0, 10), a = 1)
## $minimum
## [1] 1
##
## $objective
## [1] 4.437343e-31
V1: Suppose functions f(x, ...) and g(x , ...) can be passed different arguments. If I were to define a new function using both of them, can I make the passing of arguments via the ... operator well-defined? As a simple example:
f1 = function(x, n = 1) x + n
g1 = function(x, m = 1) x + m
f = function(x, ...) f1(x, ...)
g = function(x, ...) g1(x, ...)
h = function(x, ...) {
fgList = list()
fgList[["f"]] = f(x, ...)
fgList[["g"]] = g(x, ...)
return(fgList)
}
h(1:4)
# $f
# [1] 2 3 4 5
# $g
# [1] 2 3 4 5
h(1:4, n = 2)
# Error in g1(x, ...) : unused argument (n = 2)
The argument n is being passed down to functions f and g, but it is only well-defined for function f. I want to mitigate against this.
V2: If they are functions that I have defined, then Hong Ooi's solution below works perfectly.
Can this solution be extended for pre-defined functions which don't have a ... argument or equivalently, can a ... argument be 'added' to a predefined function which doesn't have one? For example:
h = function(x, ...) mean(x, ...) * median (x, ...)
h(1:4, test = 1)
## Error in median(x, ...) : unused argument (test = 1)
You can't have multiple versions of ... in the one environment. What you can do, however, is give each of your called sub-functions a ... argument of their own. This means they will ignore any parameters passed down that don't match their own formal arguments.
f1 = function(x, n = 1, ...) x + n
g1 = function(x, m = 1, ...) x + m
> h(1:4, n = 2)
$f
[1] 3 4 5 6
$g
[1] 2 3 4 5
Edit to answer added question: you can make a new version of median, which will override the predefined function when you call it in your own code. (Due to how R namespaces work, other predefined functions will still use the existing version.)
median <- function(x, na.rm=FALSE, ...)
base::median(x, na.rm) # function median exported from base package