我对以下构造感兴趣:
假设我有一个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
,那么是否有一个很好的R方法可以做到这一点?我知道我可以修改我的f
来处理这个替代方案,但如果有办法做到这一点,我很乐意听到这两种选择。
编辑:
评论建议for
循环实施,以便我们可以
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
}
效率更高。但我仍然觉得必须有一个更简洁的方法来做到这一点。
答案 0 :(得分:2)
如果您的功能已经是咖喱形式,那就更容易了
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
因为所有内容都是咖喱,所以您可以根据需要应用任意数量的参数,然后再应用其余的
compute <- comp2 (mult) (add)
compute (5) (6) (7)
# 7 * (6 + 5)
# 7 * 30
# 210
如果你有二进制函数列表,你可以使用左折(或#34; reduce&#34;)来创建一个完整的序列
identity <- function(x) x
comp <- function (f) function (g) function (x) f(g(x))
comp2 <- comp (comp) (comp)
uncurry <- function (f) function (x,y) f(x)(y)
reduce <- function(f) function(y) function (xs) Reduce(uncurry(f), xs, y)
comp2All <- reduce (comp2) (identity)
# some binary functions to use in our sequence
sub <- function (x) function (y) y - x
add <- function (x) function (y) y + x
mult <- function (x) function (y) y * x
# create a sequence of N binary functions
compute <- comp2All (list(mult, sub, mult, add))
# apply the computation to N+1 args
compute (3) (4) (5) (100) (0.2)
# 0.2 * (100 - (5 * (3 + 4))
# 0.2 * (100 - (5 * 7))
# 0.2 * (100 - 35)
# 0.2 * 65
# => 13
所以你可能不喜欢一次只应用一个参数...
# this kind sucks, right?
compute (3) (4) (5) (6) (7)
我们可以通过创建一个将curried函数应用于列表或参数
的函数来解决这个问题capply <- reduce (identity)
capply (compute) (3:7)
# 7 * (6 - (5 * (4 + 3)))
# 7 * (6 - (5 * 7))
# 7 * (6 - 35)
# 7 * -29
# => -203
如果你的二进制函数还没有计算:
您可以使用curry2
curry2 <- function(f) function(x) function(y) f(x,y)
curry2 (`+`) (3) (4)
# => 7
如果您有一个尚未加入咖喱的二进制函数的完整列表,则可以使用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
comp vs comp2
因为您想要创建一系列二进制函数,所以我使用了
comp2All <- reduce (comp2) (identity)
如果你想要一系列一元函数,你可以使用
compAll <- reduce (comp) (identity)
什么是comp2?
comp2定义可能看起来令人费解,但不要让它混淆你
comp2 <- comp (comp) (comp)
如果我们要扩展这一点,我们首先要看
comp2 <- function (x) comp(comp(x))
进一步扩展(这是一项有趣的练习),你应该看到
comp2 <- function (f) function (g) function (x) function (y) f(g(x)(y))
可以很容易理解为一元函数的组成, f ,具有二元函数, g