在数学中,当组合函数时,您可以使用普通的算术运算来表明这一点,例如
u = 2*x
v = log(x)
然后简单地
f = u + v
我做了很多数值工作,你必须构建复杂的数学运算。能够使用更像这样的符号会非常有帮助。例如,在R中它可能看起来像
f <- function.arithmetic('u+v', args=c('x'))
通过一些非标准评估,这可能就像
一样简单f(x) %def% u + v
其中u和v已经定义了x的函数。
有没有简单的方法来设置此语法?例如,分解表达式并用u(x)和v(x)代替它们 - 然后做一个普通的eval。 (我相信现有的解析功能比我写的一些黑客更多。而且我知道“解析”不会这样做。)
已经建议的答案可行,但它们似乎比编写
更复杂f <- function(x) u(x) + v(x)
如果表达式更复杂,这种表示法开始变得越来越难以阅读。我想设置一些更简单,更易读,更接近上述数学符号的东西。
答案 0 :(得分:4)
这是G.Grothendieck的答案,以中缀&#34; +&#34; -operator:
的形式出现 `%+%` <- function(f1, f2) { function(x) {f1(x) +f2(x)} }
f <- cos %+% sin
f
#-----
function(x) {f1(x) +f2(x)}
<environment: 0x7ffccd7eeea8>
#-------
f(0)
#[1] 1
在funprog&#39;上也有功能组合的例子。需要使用其中一个函数名称提取的页面,例如?Reduce
。也可以定义为接受其他参数:
`%+%` <- function(f1, f2) { function(x,...) {f1(x,...) +f2(x,...)} }
f2 <- dt %+% dt
#-- testing---
> f2(0)
Error in f1(x, ...) : argument "df" is missing, with no default
> f2(0, 6)
[1] 0.7654655
> dt(0,6)
[1] 0.3827328
要了解如何在内部处理此问题,您可以通过检查存储在结果闭包中的环境来恢复定义:
> ls(envir=environment(f2) )
[1] "f1" "f2"
> environment(f2)$f1
function (x, df, ncp, log = FALSE)
{
if (missing(ncp))
.Call(C_dt, x, df, log)
else .Call(C_dnt, x, df, ncp, log)
}
<bytecode: 0x7ffcc63e8ff8>
<environment: namespace:stats>
您的示例的问题在于您没有以R函数方式定义u和v。据推测,这不是您提议的用例的情况。
> u = function(x,...)2*x
> v = function(x,...) (log(x))
> f <- u %+% v
> f(4)
[1] 9.386294
Hadley的lazyeval
软件包可能支持某些编程风格:
> require(lazyeval)
Loading required package: lazyeval
> help(pac=lazyeval)
> lazy_eval(interp(~ u + v, u = sum(1:10), v=sum(1:5)) )
[1] 70
> x <- 1:10; y=1:5
> lazy_eval(interp(~ u + v, u = sum(x), v=sum(y)) )
[1] 70
> lazy_eval(interp(~ u / v, u = sum(x), v=sum(y)) )
[1] 3.666667
> lazy_eval(interp(~ log(u) / v, u = sum(x), v=sum(y)) )
[1] 0.2671555
但是我遇到了一些我无法理解的难题:
e2 <- ~ exp(u * v)/(1 + x)^2
lazy_eval(interp(e2, u = sum(x)/100, v=sum(y)/100) )
#[1] 0.271499668 0.120666519 0.067874917 0.043439947 0.030166630 0.022163238 0.016968729
#[8] 0.013407391 0.010859987 0.008975196
exp( sum(x)/100 +sum(y)/100 )/(1+x)^2
[1] 0.50343818 0.22375030 0.12585954 0.08055011 0.05593758 0.04109699 0.03146489 0.02486114
[9] 0.02013753 0.01664258
答案 1 :(得分:4)
以下是两种方法:
1)Ops / Math 这可以使用S3或S4完成。我们只说明了S3。
Compose <- function(f, g) {
if (missing(g)) structure(f, class = c("functional", "function"))
else Compose(function(...) f(g(...)))
}
Ops.functional <- function(e1, e2) {
op <- match.fun(.Generic)
Compose( if (is.numeric(e1)) function(...) op(e1, e2(...))
else if (is.numeric(e2)) function(...) op(e1(...), e2)
else function(...) op(e1(...), e2(...)))
}
Math.functional <- function(x, ...) {
op <- match.fun(.Generic)
Compose(op, x)
}
以下是两个例子:
u <- Compose(function(x) 2*x)
v <- Compose(log)
(u + v)(pi/2) # example 1
## [1] 3.593175
(exp(u*v) / (1 + u^2 + v^2)) (pi/2) # example 2
## [1] 0.3731149
注意: u
可以交替定义为u <- 2 * Compose(identity)
。事实上,我们可以定义:
Id <- Compose(identity)
u <- 2*Id
v <- log(Id)
2)定义自己的功能这不是很多工作。可能不到一页定义所有常见功能。这可以使用%...%中缀运算符来完成,但如果你真的想要使用上面的中缀路由(1)似乎更可取。因此,通过这种方法,我们保持简单。可以增强以下内容,以允许数字参数被视为常量函数,如我们在(1)中所做的那样。
Plus <- function(f, g) function(...) f(...) + g(...)
Plus(function(x) 2*x, log)(pi/2)
## [1] 3.593175