在R中使用具有高阶函数的callCC

时间:2013-10-17 15:05:41

标签: r functional-programming continuations

我正在试图找出如何获得R的callCC函数来短路函数的评估,以便使用lapply和Reduce等函数。

动机

这将使Reduce和lapply具有渐近效率> O(n),允许你 尽早退出计算。

例如,如果我在列表中搜索一个值,我可以在列表中映射一个'finder'函数,第二个找到它lapply停止运行并返回该值(就像打破循环一样,或使用return语句提前爆发。)

问题是我在编写lapply和Reduce应该使用callCC所需的样式时遇到的问题。

示例

假设我正在尝试编写一个函数来在列表中找到值'100':相当于

的东西
imperativeVersion <- function (xs) {
    for (val in xs) if (val == 100) return (val)
}

传递给lapply的函数如下所示:

find100 <- function (val) { if (val == 100) SHORT_CIRCUIT(val)  }
functionalVersion <- function (xs) lapply(xs, find100)

这(显然)崩溃,因为短路功能尚未定义。

callCC( function (SHORT_CIRCUIT) lapply(1:1000, find100) )

问题是这也会崩溃,因为当定义了find100时,短路功能并不存在。我希望有类似的东西能起作用。

以下是有效的,因为SHORT_CIRCUIT是在创建传递给lapply的函数时定义的。

callCC(
    function (SHORT_CIRCUIT) {
        lapply(1:1000, function (val) {
             if (val == 100) SHORT_CIRCUIT(val)
        })
)

如何在传递给lapply的函数中定义SHORT_CIRCUIT而不像上面那样内联定义?

我知道这个例子可以使用循环,减少或任何其他方式来实现。我正在寻找解决使用callCC与lapply和Reduce的具体问题。

如果我含糊不清或需要澄清,请在下面留言。我希望有人可以帮忙解决这个问题:)

编辑一: 方法应该是“生产质量”;没有贬值功能或类似的黑魔法。

2 个答案:

答案 0 :(得分:2)

我找到了解决这个问题的解决方案:

find100 <- function (val) {
    if (val == 100) SHORT_CIRCUIT(val)
}

short_map <- function (fn, coll) {


    callCC(function (SHORT_CIRCUIT) {

        clone_env <- new.env(parent = environment(fn))
        clone_env$SHORT_CIRCUIT <- SHORT_CIRCUIT

        environment(fn) <- clone_env
        lapply(coll, fn)

    })
}

short_map(find100, c(1,2,100,3))

使用callCC使高阶函数工作的技巧是在继续执行程序的其余部分之前将短路函数分配到输入函数环境中。我对环境进行了克隆,以避免意外的副作用。

答案 1 :(得分:0)

我不知道它是否有用,但是:

    find100 <- "function (val) { if (val == 100) SHORT_CIRCUIT(val)  }"
    callCC( function (SHORT_CIRCUIT) lapply(1:1000, eval(parse(text = find100))) )
    #[1] 100