【问题标题】:How to create a function that returns a function with different arguments?如何创建一个返回具有不同参数的函数的函数?
【发布时间】:2017-04-05 16:39:34
【问题描述】:

我正在尝试在 R 中编写一个函数,该函数接受两个函数(使用可以视为相同的参数定义),将它们相乘并返回在某个新点评估的乘积上的积分。现在,将函数相乘并不难,这里的问题在于,我不想评估参数x 中的函数之一,而是想在w/x 中评估它,其中w 是新参数(但我只想在功能产品中这样做)。这是我的代码:

    "%*f%" <- function(a,b) {
        force(a)
        force(b)
        function(x){a(x) * b(x)}
    }

    pdf_product <- function(pdf1, pdf2) {
        pdf3 <- function(x,w) {pdf2(w/x)}

        myfun <- function(x,w) {
            (1/abs(x)) %*f% pdf1(x) %*f% pdf3(x,w)
        }

        function(w) {
           sapply(w, function(w) {
               integrate(function(x) myfun(x,w), llim, ulim)$value
           })
        }
    }

    pdf1 <- function(x) {1/(2-1)} #simple function example1
    pdf2 <- function(x) {1/(6-3)} #simple function example2
    llim <- 1 #lower limit integral
    ulim <- 2 #upper limit integral

    prod <- pdf_product(pdf1, pdf2)
    prod(4) #should evaluate to 0.09589402

我知道pdf_product 的最后一部分工作正常,给定一个工作函数myfun(因为这是在 R 中运行二维函数上的单个积分的方式 - 但如果我错了,请纠正我)。但是,如果我运行上面的代码,我会收到以下错误消息(带有回溯):

    Error in integrate(function(x) myfun(x, w), llim, ulim) : 
      evaluation of function gave a result of wrong length 
    5.
    integrate(function(x) myfun(x, w), llim, ulim) 
    4.
    FUN(X[[i]], ...) 
    3.
    lapply(X = X, FUN = FUN, ...) 
    2.
    sapply(w, function(w) {
        integrate(function(x) myfun(x, w), llim, ulim)$value
    }) 
    1.
    prod(4) 

我感觉这个错误与我通过从pdf2 定义pdf3 引入的“变量更改”有关,但我找不到修复它的方法。我曾尝试在 %*f% 返回的函数中使用著名的 R 三点原理,但这也不起作用。

【问题讨论】:

  • 我很困惑。您的 "%*f%" 组成函数,但在 (1/abs(x)) %*f% pdf1(x) %*f% pdf3(x,w) 中,您不会将函数传递给它。 1/abs(x) 返回一个值。
  • 啊,我明白你的意思了,谢谢。但是如果我改变它,错误信息就会从上面变成unused argument w。

标签: r function arguments


【解决方案1】:

所以,你的问题是你想组合两个函数,但这些函数可以有两个以上的参数。这可能有用:

"%*f%" <- function(a,b, ...) {
  force(a)
  force(b)
  if (length(formals(args(a))) > 1L && 
      length(formals(args(b))) > 1L)
    stop("Only one function with additional parameters allowed.")
  if (length(formals(args(a))) == 1L && 
      length(formals(args(b))) > 1L)
    return(function(x, ...){a(x) * b(x, ...)})
  if (length(formals(args(a))) > 1L && 
      length(formals(args(b))) == 1L)
    return(function(x, ...){a(x, ...) * b(x)})
  if (length(formals(args(a))) == 1L && 
      length(formals(args(b))) == 1L)
    return(function(x){a(x) * b(x)})
  stop("Function without parameters passed")
}

(sign %*f% abs)(-5)
#[1] -5
(sign %*f% `+`)(-5, 1)
#[1] 4

请注意,如果两个函数都可以有多个参数,您需要设计一种不同的方式来传递这些参数:

"%*f%" <- function(a,b, args1 = NULL, args2 = NULL) {
  stopifnot(is.list(args1) | is.null(args1))
  stopifnot(is.list(args2) | is.null(args2))
  force(a)
  force(b)
  if (length(formals(args(a))) > 1L && 
      length(formals(args(b))) > 1L)
    return(function(x, args1, args2) do.call(a, c(x, args1)) * do.call(b, c(x, args2)))
  #code for the other cases
}

(`^` %*f% `+`)(-5, list(2), list(1))
#[1] -100

如果你是管道爱好者,那么研究一下使用包 magrittr 可能会更好。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-05-13
    • 2016-10-12
    • 1970-01-01
    • 2021-07-03
    • 1970-01-01
    • 2012-09-26
    • 1970-01-01
    • 2019-04-15
    相关资源
    最近更新 更多