Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/r/78.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
R 如何链接二进制函数列表_R_Function_Functional Programming - Fatal编程技术网

R 如何链接二进制函数列表

R 如何链接二进制函数列表,r,function,functional-programming,R,Function,Functional Programming,我对以下结构感兴趣: 假设我有一个n二进制函数列表和一个n+1参数向量。为方便起见,让我们使用 flist = c(`+`,`-`) args = 1:3 我想做的是创建以下函数调用f2(f1(x1,x2),x3),即在本例中 `-`(`+`(1,2),3) 其中,返回值是累积结果的向量 [1] 3 0 我有一个形式的解决方案 f = function(x,op,res = NULL){ if(is.null(res)){ res = op[[1]](x[1],x[2])

我对以下结构感兴趣:

假设我有一个
n
二进制函数列表和一个
n+1
参数向量。为方便起见,让我们使用

flist = c(`+`,`-`)
args = 1:3
我想做的是创建以下函数调用f2(f1(x1,x2),x3),即在本例中

`-`(`+`(1,2),3)
其中,返回值是累积结果的向量

[1] 3 0
我有一个形式的解决方案

f = function(x,op,res = NULL){
  if(is.null(res)){
    res = op[[1]](x[1],x[2])
    x = x[-1]
  } else{
    res = c(res,op[[1]](res[length(res)],x[1]))
  }
  if(length(op) == 1) res
  else f(x[-1],op[-1],res)
}
这就是正确答案

f(x,flist)
[1] 3 0
但它感觉不到特别的浪漫和优雅。有没有更好的办法。我怀疑我的实现也不是最高效的,因此任何更高效的东西都会引起人们的兴趣

有人有什么想法吗

或者,如果放宽了累积答案的要求,即只返回最终答案
0
,是否有一个好办法?我知道我可以修改我的
f
来处理这个替代方案,但是如果已经有一种方法可以做到这一点,我很乐意听到任何一种选择

编辑:

一条评论建议对循环实现使用
,这样我们就可以

falt = function(x,op){
  res = numeric(length(op))
  res[1] = op[[1]](x[1],x[2])
  for(i in 2:length(res)) res[i] = op[[i]](res[i-1],x[i+1])
  res
}

这样做会更有效率。但我仍然觉得必须有一种更简洁的方法来实现这一点。

如果您的函数已经是咖喱格式的,那么就容易多了

comp <- function (f) function (g) function (x) f(g(x))

comp2 <- comp (comp) (comp) # if this is confusing, details later

add <- function (x) function (y) y + x
mult <- function (x) function (y) y * x

comp2 (mult) (add) (3) (4) (5)
# 5 * (4 + 3)
# 5 * 7
# 35
我们可以通过创建一个函数,将curried函数应用于列表或参数来解决这个问题

capply <- reduce (identity)
capply (compute) (3:7)
# 7 * (6 - (5 * (4 + 3)))
# 7 * (6 - (5 * 7))
# 7 * (6 - 35)
# 7 * -29
# => -203
如果您有一个尚未使用的二进制函数的完整列表,则可以使用
map

map <- function (f) function (xs) Map(f,xs)
compute <- comp2All (map (curry2) (list (`*`, `+`, `*`, `+`)))
compute (3) (4) (5) (6) (7)
# 7 * (6 + (5 * (3 + 4)))
# 7 * (6 + (5 * 7))
# 7 * (6 + 35)
# 7 * 41
# => 287

map为什么使用递归和增长
res
?只需为
循环使用一个
,并将res预分配到最终大小。这没有什么特别的原因,我目前正在学习scala,因此递归在我的脑海中占据了很多位置。一个使用
for
循环的实现效果不错,而且速度更快,而在R中,深度递归是不好的,所以这是一个合理的建议。尽管如此,感觉好像应该存在某种不错的reduce操作。个人抱怨,但我也不喜欢R中的
循环,因为它的功能性和矢量化性质。我也暂时忘记了在R中增长对象的愚蠢。您想查看Reduce文档吗?搜索Iterate…这可能会有所帮助Hadley的“Advanced R”一书中还有一节关于函数编程的内容感谢@chinsoon12的评论。我刚刚重读了Hadley的书中的函数编程部分,虽然我意识到将函数列表应用到给定的输入是相对简单的,但我不知道如何将其扩展到我想在这里做的事情。我现在正在检查
?Reduce
文档,看看是否可以操纵迭代示例来实现我的目标。我总体上喜欢这个外观,并且可以看到如何将它应用到我的最小示例中。如何将其扩展到一般情况,比如说
n
函数和
n+1
参数列表来自其他机制。如果
n
很大,我不想担心函数是什么,甚至不想担心列表的长度。所有函数都是二进制函数吗?它们是已经用咖喱做的,还是你可以用咖喱做的?这里的所有函数都是二进制的是,但一般来说不是咖喱形式。我尝试了最后一个示例,用
f
g
替换带有参数
x
y
的已定义二进制函数,但如上所述使用它,我得到了缺少参数的错误。我目前也不知道如何避免键入类似于
comp2(Curry(flist[[1]])(Curry(flist[[2])的内容(…
这是我显然想要避免的。@jamieRowen当然,当您添加各种转换时,创建表示每个特定转换的函数是有意义的。这样,只要您希望利用该转换,函数就可以重用。
map
将函数
f
应用于列表,并且
reduce
将在列表中的每个元素之间折叠一个函数。有关更多详细信息,请参阅更新的答案。如果您有更多问题,请提问:)很抱歉,我花了这么长时间才回到这个问题上来,我被别的事情弄得支离破碎,暂时忘记了这件事。我也花了一点时间才完全理解你的答案,但我喜欢它。
# this kind sucks, right?
compute (3) (4) (5) (6) (7)
capply <- reduce (identity)
capply (compute) (3:7)
# 7 * (6 - (5 * (4 + 3)))
# 7 * (6 - (5 * 7))
# 7 * (6 - 35)
# 7 * -29
# => -203
curry2 <- function(f) function(x) function(y) f(x,y)
curry2 (`+`) (3) (4)
# => 7
map <- function (f) function (xs) Map(f,xs)
compute <- comp2All (map (curry2) (list (`*`, `+`, `*`, `+`)))
compute (3) (4) (5) (6) (7)
# 7 * (6 + (5 * (3 + 4)))
# 7 * (6 + (5 * 7))
# 7 * (6 + 35)
# 7 * 41
# => 287
comp2All <- reduce (comp2) (identity)
compAll <- reduce (comp) (identity)
comp2 <- comp (comp) (comp)
comp2 <- function (x) comp(comp(x))
comp2 <- function (f) function (g) function (x) function (y) f(g(x)(y))