wglaive 想写一个函数,在有特定变量名的时候执行特定的功能。 伪代码例子如下: f=function(...) { if (hasArg("plus")) { return (plus[1]+plus[2]) } if (hasArg("minus")) { return (minus[2]-minus[1]) } } 调用的时候就 f(plus=c(1,2)) 思路是这样,当然如上代码在r里面肯定跑不通, 第一个问题是hasArg能检测到有该名字到变量但是没法直接解放到环境中,查了资料发现需要用list x=list(...) 于是修改如下: f=function(...) { x=list(...) if (hasArg("plus")) { return (x$plus[1]+x$plus[2]) } if (hasArg("minus")) { return (x$minus[2]-x$minus[1]) } } 但是感觉这样额外做了一道转换,有更优雅的办法吗
yihui wglaive 为什么不把这个函数拆分为两个函数呢?我感觉这里用技巧不如下拙力。通常来说我是倾向于 UNIX 设计原则:一个函数(或一个命令)做一件事。杂糅很容易带来麻烦,例如你要为这个“聪明”的函数写特别的文档,扯不开的代码也不利于单元测试。 可能你还得再深入介绍一下你的原始目的是什么,然后再考虑手段。
tctcab wglaive 想想六个月后看到这代码会不会想打死自己,拆两个函数就少了两个if判断。 函数参数还是尽量写清楚函数名,哪些适合...哪些不适合。你这个参数可以写成 function(operator=c("plus", "minus")){ operator=match.args(operator) } 另外,从list里判断是否包含元素是一个很昂贵的操作,非得做的话,改成 if (any(names(...)=="plus")){}会快一点
wglaive yihui 原始目的是想用泛型的思路写函数。想要达到的目的是分析模型object的时候一个函数搞定,不然太多太乱了记不住。。。。从目前来看有两个情况,一个是模拟数据分析,需要和真实值做对比,一个是真实数据分析,需要和其他包做对比。和其他包计算函数我的计算函数的input的数据集有些不一样,做过预处理。这样的话模拟数据分析的时候,需要一个input真实值。真实数据分析的时候需要input原始变量。 那我就想函数调用的时候input是theta0就调用模拟比较,input是data0就调用别人的包做比较。语死早于是伪代码如下: analysisPlot=function(result,...) { 预测值=predict(result) if (hasArg("theta0")) 比较值=predict(theta0) if (hasArg("data0")) 比较值=predict(别人的包(data0)) plot(预测值) line(比较值) }
tctcab wglaive 看上去是个项目代码管理的问题。 数据分析的话其实还是得注意整理代码。结合Rmarkdown+ R package,用git做好版本控制,如yihui 所说让函数功能尽量简单。 这方面我记得看到过几篇不错的blog介绍基于Rmarkdown的工作流程,找到的话会贴过来。 关于代码整理的话,我是在一个Rstudio的project下有个R/的目录专门放函数代码,然后有个notebook/的目录放Rmarkdown的数据分析记录,包括数据清理注释,作图做表。图表在单独保存在rdata/xxx.rda 下,然后在写文章的时候加载这些图表微调一下就好。
nan.xiao 楼主的问题有点具体,我有个抽象一些的用例:一个高度过程式的计算流程,存在很多可选参数,并且需要在流程中间对参数甚至参数的组合产生的条件进行判断 …… 在工程实现上需要解耦,使得整体逻辑更加清晰可维护。 这类问题的简单解法基本就是利用 match.call() 捕捉参数,然后就可以把所有参数当作 list 中的数据进行操作了。一个例子可以参考 ashr 中的 R/ash.R 和 R/process_args.R。 不过 match.call() 也有局限,所以扩展下去需要各种黑魔法也很正常。 当然,这个问题在很多时候是可以通过把流程中的逻辑拆分成很多简单函数,层层调用来实现的。这样可以提高代码的重用,也更贴近函数式编程理念。如果你读过 RStudio 早期员工的代码,就会发现这种风格十分突出。
wglaive tctcab 还有一个扩展的问题,比如我拓展原始函数,加一个要用到这个函数环境的功能,这时候多加一个if就能完成的扩展,还不影响之前函数的功能,和之前所有可能用到的调用。。。。 提前感谢搬运🙏
yusong 有一个思路,比如这样: f <- function(action) { function(x, y) { action(x,y) } } add <- function(x,y) x + y minus <- function(x,y) x - y f(add)(3,4) f(minus)(3,4) 我暂时看不到这样做的意义在哪,但是希望能对你有所启发。如果感兴趣可以搜一下Function factories。
wglaive https://stackoverflow.com/questions/28370249/correct-way-to-specifiy-optional-arguments-in-r-functions This seems provide enough options....