【问题标题】:Undefined subroutine &PDL::divide未定义的子程序 &PDL::divide
【发布时间】:2019-08-11 00:24:49
【问题描述】:

我正在以下代码中尝试 Perl 的 PDL:

#!/usr/bin/perl  -w
use strict;
use PDL::Core qw(pdl);
use PDL::Math qw(isfinite);
use PDL::Primitive qw(statsover);


my $div = 4;
my @array1 = (0..10);
my $pdl_array = log(pdl(@array1)/$div);
$pdl_array->where(!isfinite($pdl_array)) .= 0;
my($mean,$stdev) = statsover($pdl_array);
die $pdl_array,"\n",$mean," ",$stdev,"\n";

我收到了这个错误:

在 ./compare_const.pl 第 10 行调用的未定义子例程 &PDL::divide。

有什么提示吗?非常感谢。

【问题讨论】:

    标签: perl perl-module pdl


    【解决方案1】:

    PDL 的设计不寻常,因此具有不寻常且有些脆弱的导入机制。每个 PDL 模块都通过inserting a new method directly into PDL's package 向 PDL 添加功能。这一决定是在 PDL v2 设计的早期做出的,并且在随后的十年中没有改变。 (没有理由不能对其进行更改,即使以向后兼容的方式也是如此,但没有一个 PDL 开发人员留出时间来这样做。)

    因此,您必须加载少量模块以确保 PDL 具有其必需的基本功能。如果您查看 PDL 的导入功能,您会注意到 it explicitly loads a number of packages into the caller's namespace。这样做的原因是好的——在多个模块之间拆分功能以保持分布健全——但实现与常见的 Perl 实践不一致。这就是您尝试将特定函数导入命名空间失败的原因。

    解决方案已经解释过了。要么用一个 use PDL 替换所有 use PDL::... 语句:

    use strict;
    use warnings;
    use PDL;
    
    my $div = 4;
    ...
    

    或者说use PDL::Lite(保证PDL的包是完整的)然后将具体功能导入你的(主)包中

    use strict;
    use warnings;
    
    use PDL::Lite;
    use PDL::Core qw(pdl);
    use PDL::Math qw(isfinite);
    use PDL::Primitive qw(statsover);
    
    my $div = 4;
    ...
    

    【讨论】:

      【解决方案2】:

      只需添加use PDL;,您的代码就可以工作:

      #!/usr/bin/perl  -w
      use strict;
      
      use PDL;
      use PDL::Core qw(pdl);
      use PDL::Math qw(isfinite);
      use PDL::Primitive qw(statsover);
      
      my $div = 4;
      my @array1 = (0..10);
      my $pdl_array = log( pdl(@array1) / $div );
      $pdl_array->where(!isfinite($pdl_array)) .= 0;
      my ($mean, $stdev) = statsover($pdl_array);
      die $pdl_array, "\n", $mean, " ", $stdev, "\n";
      

      输出:

      [0 -1.3862944 -0.69314718 -0.28768207 0 0.22314355 0.40546511 0.55961579 0.69314718 0.81093022 0.91629073]
      0.112860814716055 0.696414187766251
      

      【讨论】:

      • 确实有效。谢谢!但是编译器将除法运算分配给 PDL 的任何原因?
      【解决方案3】:

      PDL 有一组最少的必须加载的东西。要正确加载这些内容,您必须要么use PDL(它还导出一堆东西)要么use PDL::Lite

      (出于某种原因,我认为您直接显式调用 PDL::divide 并收到该错误,因此下面是我的原始答案。)

      原答案:

      我想知道为什么你认为应该有效?

      是的,PDL 会导出一堆东西(如果你使用它,你不会),但这并不能保证它从哪里导出它。 (事实上​​,它似乎从许多不同的地方直接导出到使用包中。)

      如果你想避免命名空间污染,我建议要么导入指定的包并使用那里的东西:

      {
          package My::PDL;
          use PDL;
      }
      ...
      My::PDL::divide...
      

      或使用 OO 接口(我认为请参阅 PDL::Lite?)

      【讨论】:

      • Thenks @ysth。知道为什么分裂应该位于 PDL 中吗?
      • 不是,而且我没有看到任何说明它的文档。
      • 啊,我误解了原来的问题;编辑我的答案。
      • ysth,小错字:你说PDF::divide。我试图通过编辑来修正你的错字,但 stackoverflow 不允许。
      猜你喜欢
      • 1970-01-01
      • 2013-06-25
      • 2017-02-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-07
      • 2015-10-22
      相关资源
      最近更新 更多