2

有没有办法让我从我的来电者那里返回而不是我的来电者?例如

sub foo {
    bar();
    # this never gets executed
}

sub bar {
    return_from_caller(5);
}

# This prints 5
print foo();

(基本原理:我正在编写一个函数 memoize_self,它从函数本身中记住一个函数。我希望它像这样工作:

sub complex_function {
    my ($x, $y) = @_;
    memoize_self({key => $y, expires_in => '5min'));
    # compute $result
    return $result;
}

memoize_self 将检查其缓存,如果命中,则从其调用者返回缓存值。否则,它将重新调用该函数(使用动态范围的 var 以避免明显的无限循环),将返回值存储在缓存中并再次返回它。

如果没有从调用者返回的能力,我可能会使用 $_ 并这样写:

return $_ if memoize_self({key => $y, expires_in => '5min'));

但这是额外的噪音,也没有考虑上下文。)

编辑:对于那些合理地建议Memoize的人——是的,我应该说,我很了解这个模块。我正在写一个基于CHI的更现代、更有特色的 Memoize 版本。

但就这个问题而言,在某些情况下,从函数内部而不是函数外部进行记忆是有用的(记忆只做后者)。它可以很容易地自定义缓存键和/或确定是否要为这个特定的调用进行记忆。例如

sub complex_function {
    my $key = ...;   # normalize arguments
    if (...) {       # is it worth memoizing in this case?
        memoize_self({key => $key});
    }
}

我也喜欢它被包裹在函数中的方式,而不是在外部创建自己的行,ala state variables

4

4 回答 4

7

Continuation::Escape完全符合您的要求。然而,正如 Nikhil 指出的那样,Memoize是你真正需要的。

于 2012-04-29T13:25:57.530 回答
1

看看 CPAN 模块Memoize - 通过空间换时间使功能更快,这可能会解决您的问题。

于 2012-04-29T12:57:17.430 回答
0

“有没有办法让我从我的呼叫者那里返回而不是我的呼叫者?”

是的,有几个。

  • 你可以goto用来跳回来。见perldoc -f goto
  • 您可以使用evaldie进行更多控制跳转。见perldoc -f evalperldoc -f die
  • 而不是以正常方式调用您的子,您可以goto。当你这样做时,它将与goto调用者一起返回到 sub。见perldoc -f goto

当然,大多数人会告诉您重写所有内容以避免 goto 并使维护代码的人的生活更轻松,但是他们为您做过什么?

于 2012-04-29T14:35:05.127 回答
0

另一种解决方案是使用 Want 模块的 double_return 方法,这会使您的下一个返回弹出两个调用帧:

#!/usr/bin/env perl
use warnings;
use strict;

use Want;

sub foo {
    Want::double_return;
    return 11;
}
sub bar { 
    foo();
    # never executed
    return 55;
}

# prints 11;
print bar();
于 2012-04-29T17:50:17.170 回答