我如何将参数(名称)传递给函数工厂? [英] how can I pass argument (names) to a function factory?

查看:226
本文介绍了我如何将参数(名称)传递给函数工厂?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要构建许多具有许多不同参数的函数,尽管它们共享很多代码和结构。
为了避免重复,我认为自己会很聪明,自己构建一个函数工厂(aka closure)。

我无法弄清楚如何在函数工厂内传递函数参数。



我的用例是一堆S3构造函数,它们共享相同的验证机制。
所以我用这个例子来解释我的问题。



说,我有一个 ClassA ClassB ,它们中的每一个在各自的构造函数中都需要自己的参数:

  ClassA < - 函数(A_arg1,A_arg2){
#发生了一些特定类的构造魔术,比如
out < - list(A_arg1,A_arg2)

#some一般建筑魔术发生
class(out)< - ClassA

return(out)
}

ClassB< - 函数(B_arg1,B_arg2){
#一些特定类的建筑魔术发生,比如
out< - B_arg1 + B_arg2

# b班(out)< - ClassB

返回(出)
}

很明显,我很想避免构造函数的 general 部分中的重复,所以可以像一样使用的函数工厂会很好:

  ClassA < -  produce_class_constructor(classname =ClassA,fun = function(A_arg1,A_arg2){return(list(A_arg1,A_arg2))})

理想情况下,这应该产生与上面手动构建的完全相同的功能 ClassA 函数,并将其中的一般部分分解出来。



这是我在构建函数工厂时的尝试

  produce_class_constructor<  -  function(classname,fun){
class_specific_arguments< - formals(fun = fun)#这可以在控制台上正常工作
construct_class< - 函数(class_specific_arguments){
#在这里运行特定于类的东西
out< - fun(class_specific_arguments)


class(out)< - classname
}
}

然而,这是行不通的,因为结果构造函数只有一个 class_specific_arguments -argument,而不是实际的 A_arg1 A_arg2



有没有办法做到这一点?
我是否做错了?



(这对我来说非常重要,因为结果类构造函数具有正确命名的参数,所以


解决方案

这是我的尝试:

  produce_class_constructor<  -  function(classname,fun){
out_fun< - function(){
out_obj< - do.call(fun,as.list(environment()))
class(out_obj)< - classname
out_obj
}
formals(out_fun)< - formals (fun)
out_fun
}

ClassA < - produce_class_constructor(classname =ClassA,
fun = function(A_arg1,A_arg2){list(A_arg1, A_arg2)})
ClassA(1,2)
#[[1]]
#[1] 1

#[[2]]



#attr(,class)
#[1]ClassA

ClassB < - produce_class_constructor(classname =ClassB,
fun = function(B_arg1,B_arg2){B_arg1 + B_arg2})
ClassB(B_arg2 = 2,1)
#[1] 3
#attr(,class)
#[1]ClassB

使用 as.list(environment())来自这个问题。请注意,您应该特别注意沿着该路径,因为?formals 说,这是
高级危险编码。


I need to build a lot of functions with lots of different arguments, though they otherwise share a lot of code and structure. To avoid duplication, I thought I'd be clever and build myself a function factory (aka closure).

I can't figure out how to pass the function arguments inside the function factory.

My use case is a bunch of S3 constructor functions, all of which share the same validation mechanism. So I'll use that as an example to explain my problem.

Say, I have a ClassA and ClassB, each of which require their own arguments in the respective constructor functions:

ClassA <- function(A_arg1, A_arg2) {
  # some class-SPECIFIC construction magic happens, say
  out <- list(A_arg1, A_arg2)

  # some GENERAL construction magic happens
  class(out) <- "ClassA"

  return(out)
}

ClassB <- function(B_arg1, B_arg2) {
  # some class-SPECIFIC construction magic happens, say
  out <- B_arg1 + B_arg2

  # some GENERAL construction magic happens
  class(out) <- "ClassB"

  return(out)
}

Obviously, I'd love to avoid the duplication in the general part of the constructor functions, so a function factory that could be used like so would be nice:

ClassA <- produce_class_constructor(classname = "ClassA", fun = function(A_arg1, A_arg2) {return(list(A_arg1, A_arg2))})

This should, ideally, yield the exact same function as the above manually constructed ClassA function, with the general part factored out.

Here's my attempt at building that function factory:

produce_class_constructor <- function(classname, fun) {
  class_specific_arguments <- formals(fun = fun)  # this works just fine on the console
  construct_class <- function(class_specific_arguments) {
    # here runs the class-specific stuff
    out <- fun(class_specific_arguments)

    # here runs the general stuff
    class(out) <- classname
  }
}

This however, does not work, because the resulting constructor function only has a class_specific_arguments-argument, not the, well, actual A_arg1, and A_arg2.

Is there way to do this? Am I doing this wrong?

(It's really important to me that the resulting class constructor functions have properly named arguments, so a ... approach won't work).

解决方案

Here's my attempt:

produce_class_constructor <- function(classname, fun) {
  out_fun <- function() {
    out_obj <- do.call(fun, as.list(environment()))
    class(out_obj) <- classname
    out_obj
  }
  formals(out_fun) <- formals(fun)
  out_fun
}

ClassA <- produce_class_constructor(classname = "ClassA", 
  fun = function(A_arg1, A_arg2) {list(A_arg1, A_arg2)})
ClassA(1, 2)
#[[1]]
#[1] 1
#
#[[2]]
#[1] 2
#
#attr(,"class")
#[1] "ClassA"

ClassB <- produce_class_constructor(classname = "ClassB", 
  fun = function(B_arg1, B_arg2) {B_arg1 + B_arg2})
ClassB(B_arg2 = 2, 1)
#[1] 3
#attr(,"class")
#[1] "ClassB"

Idea with as.list(environment()) taken from this question. Note that you should be extra careful along that path, as ?formals says, "this is advanced, dangerous coding".

这篇关于我如何将参数(名称)传递给函数工厂?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆