【问题标题】:Perl6: getting array ref for Perl5 ModulePerl6:获取 Perl5 模块的数组引用
【发布时间】:2019-02-18 16:14:48
【问题描述】:

我正在尝试使用 Excel::Writer::XLSX 在 Perl6 中编写 Excel 笔记本。

我通过 use Excel::Writer::XLSX:from<Perl5> 使用 Inline::Perl5

具体来说,我想像在 Perl5 中那样写一行:

$worksheet -> write_row(0,0, \@line);

但这会出错

要在 Perl 6 中将数组、散列或子函数传递给函数,只需将其传递为 是。对于 Perl 5 的 ref 运算符的其他用途,请考虑使用 ::= 进行绑定 反而。如果您打算捕获单个 变量。

所以我尝试了建议1:

$worksheet.write_row(0,0, @line)

报错

在 -e 第 0 行调用 write_row() 时不是数组引用。

建议2:

$worksheet.write_row(0,0, ::=@line);

在 -e 第 0 行调用 write_row() 时不是数组引用。

$worksheet.write_row(0,0, (@line));

这给出了相同的错误。

如何在 Perl6 中使用 Excel::Writer::XLSX 将数组写入一行?

【问题讨论】:

  • 你好。请尝试$worksheet.write_row(0,0, $@line)。如果可行,我会写下答案。
  • @raiph 确实有效。我会尽快接受你的回答
  • @raiph \(@line) 产生与其他方法相同的错误

标签: raku


【解决方案1】:

解决办法是写$@array而不是\@array

$worksheet.write_row(0,0, $@line)

本答案的其余部分是关于使用已安装的外语适配器编写代码并处理出现的任何问题的简要指南。我打算把它作为一个通用资源,一个远远超出这个特定问题的答案。

它以明显的问题“为什么$@foo?”开始,讨论如何成功使用外语适配器,最后解释为什么警告消息没有帮助。

为什么是$@foo

编写$@foo 以将@foo 作为数组引用 传递给P5 是对现有P6 功能的简单而自然的使用。

也就是说,用户不需要了解 P6 的这个 $ 特性,也不需要知道 Inline::Perl5 是如何使用它的,就可以完成他们想做的事情(编写传递数组的 P6 代码引用 P5 模块中的函数)。

所以“为什么是$@foo?”的主要答案是你那样写它并且它有效。 \o/

一个人应该怎么知道魔法咒语?

我得到了从Inline::Perl5's README 传递数组引用的解决方案:

HASHARRAY 如果 Perl 6 对象被容器化,则会自动进行引用:

$p5obj.takes-an-array:      [<a b c>];
$p5obj.takes-an-array-ref: $[<a b c>];

(“集装箱化”这个词指的是一个 P6 概念,lizmat 在她的Containers in P6 文章中为那些了解 P5 的人很好地解释了。但实际上集装箱船在技术上与 为什么 $@foo 的意思并不相关使用 Inline::Perl5 时在 P5 中的数组引用。是的,它有效。不,它不必那样。)

为什么 P6 中的 $@foo 表示 P5 中的数组引用?

之所以写$@foo正确,并不是因为 P6 语言或编译器这么说。

一个合适的 P6 功能,但它是正确的原因是niner(Inline::Perl5的作者) 这么说。

niner为什么选择$@foo

大概是因为:

  • 对新手来说很容易写;

  • 当有人了解 P6 时,这将是有意义的;

  • 易于记录;

  • 很容易以高效的方式从其 P6 含义(Scalar 中的 Array)转换为目标 P5 含义(P5 数组引用)。

使用外语适配器时会发生什么

Inline::Perl5 是几个foreign language adaptors 之一。这些适配器允许 P6 代码嵌入以这些外语编写的代码和/或使用以这些外语编写的模块。

当 Rakudo P6 编译器在 use 语句中看到 :from&lt;Perl5&gt; 时,它会隐式调用先前安装的名为 Inline::Perl5 的 P6 模块。

Inline::Perl5 安装 marshaling 代码,该代码自动将 P6 代码映射到 P5 代码和从 P5 代码映射,因此 P6 和 P5 可以轻松地协同工作。

理想情况下,适配器只会完成他们的工作,而您永远不必考虑它们。但是:

  • 虽然将 P6 中的 42 映射到任何和所有外语中的显而易见的事情是它们表示整数 42 的值,但对于更高级别的数据结构,映射并不总是那么简单,函数、引用等。有时编写 P6 代码可以完成令人惊奇的事情(您可以创建一个 P6 类,它是 P5 类的子类,就像使用常规 P6 代码一样编写它!)但有时您有遵循规则(如在本例中如何将 P6 数组作为数组引用传递给 P5)。请参阅下面的适配器文档部分。

  • P6 语言和编译器不知道映射正在进行。因此,它们显示的任何错误或警告消息都可能无济于事,甚至具有误导性。此外,适配器错误与 P6、其编译器和正在使用的外语模块中的错误是分开的。请参阅下面的警告和错误部分。

使外语适配器进行的自动映射远非自动。有才华的开发人员必须编写适配器代码来完成所有数据、异常等的封送处理。

如果经过足够长的时间(年),适配器可能会接近理想状态,如果您只想在 P6 中使用该语言的模块或代码,则无需考虑适配器的存在。您只需使用它,它就始终像在外语中一样工作。

亲爱的读者,对我们所有人来说,一种更快接近理想的方法是通过现有适配器使用外部模块,并在特定功能似乎不起作用时编写 SO 问题和文件问题.感谢@con、niner 以及所有让这一切发生的人。

适配器文档

确定您应该编写什么 P6 代码以使用您通过 :from&lt;...&gt; 使用过的外语模块的唯一方法是:

  • 阅读外语模块的文档以了解它的预期;然后

  • 阅读适配器的文档,了解如何编写相应的 P6 代码,为外语和外语模块提供他们所期望的。

在本例中,我们正在讨论:from&lt;Perl5&gt; 的使用,适配器为Inline::Perl5。它的文档目前是its github project repo README。因此,要了解您应该写什么来为 P5 和 P5 模块提供他们所期望的内容,请阅读该文档。

每个适配器都有自己的文档;在modules.perl6.org 上查看其列表以获取链接。

警告和错误

如果在 P6 中使用外语模块时出现任何问题(直接在该外语中使用相同的代码时不会出现问题),那么:

  • 确保您已阅读相关适配器的文档;

  • 如果您收到警告或错误消息,请务必参阅适配器的文档及其问题队列,以查看它是否能阐明该特定消息;

  • 如果您认为在使用直接用于该外语时可以正常工作的外语模块时,在 P6 中的工作方式(或不正常)存在错误,请参阅适配器的问题队列。例如,如果您使用的是:from&lt;Perl5&gt;,请参阅Inline::Perl5's issue queue。如果您决定发布某些内容,如果您不确定这是一个错误,请在此处发布,或者如果您是,请在适配器的问题队列中发布。

由于 P6 语言和编译器不知道映射正在进行,警告和错误消息可能会在学习使用涉及以下规则的外语适配器的任何方面的上下文中产生误导,例如 $@foo这个 SO 的规则。

在 P5 问题的情况下,如果 P6 试图帮助 P5 编码人员编写 P6 代码,并且在使用 Inline::Perl5 时尝试适得其反,这可能会加剧这种情况。问题中的例子就是一个很好的例子:

To pass an array, hash or sub to a function in Perl 6, just pass it as is.

P6 认为您可能习惯于使用前缀 \ 编写数组引用。它认为您可能没有意识到您不需要在 P6 中编写斜线。它没有意识到你在坚持通过Inline::Perl5 获取 P5 可以理解的数组引用。

For other uses of Perl 5's ref operator consider binding with ::= instead.

P6 认为你正在尝试做 P5 中通常使用 \ 完成的事情,不是因为你想使用 P5,而是因为你知道 P5,想要在 P6 中完成一些事情而不涉及 P5,并希望完全相同的语法有效。

(顺便说一句,::= 建议肯定帮不上忙——因为::= 还没有实现!)

Parenthesize as (...) if you intended a capture of a single variable.

P6 并不认为您正在尝试使 P5 函数与数组引用一起工作。它认为您正在尝试创建 P6 Capture

它的建议应该被解释为建议你写\(@foo)而不是\@foo来创建一个包含@fooCapture

它已经警告使用 \@foo 来表示 Capture 正是因为 P5 开发人员可能会认为它会创建一个数组引用来编写它。

总之,P6 不知道Inline::Perl5 的存在,也不知道它会对您的代码做任何事情。相反,它的建议是尝试将它认为您正在使用的 P5 语法和概念转换为 P6 中相应的语法和概念。 不是试图建议如何编写适合映射到 P5 的 P6 代码通过Inline::Perl5

总而言之,我想适配器开发人员和核心 P6 开发人员有可能有一天会根据此 SO 提出的可用性问题修改 P5 相关的警告和错误消息。

【讨论】:

    【解决方案2】:

    ::= 是一个中缀运算符,因此您需要在它的左侧添加一些东西。如果您使用它,您会发现它还没有实现。不过这没关系,因为它仍然无济于事。

    编译器抱怨是因为您编写的代码看起来像 Perl5 而不是 Perl6。它不知道你真正想要完成什么。


    在 Perl5 \ 创建一个引用。在 Perl6 中并没有这样的东西。

    use v5.12;
    
    my @a;
    my $a = \@a;
    say ref $a; # ARRAY
    say ref \$a; # REF
    

    在 Perl6 中,\ 用于创建 Capture。

    use v6.d;
    
    my @a;
    my $a = \(@a);
    say $a.^name; # Capture
    

    由于 Perl5 没有 Capture 而 Perl6 也没有 REF,所以接口层将 Capture 转换为 REF 以供 Perl5 使用。

    Perl6 中的数组已经是一种引用,所以 Perl6 中的 \(@a) 就像 Perl5 中的 \\@a


    作为一种测试方式,我将使用 Scalar::Util::reftype。

    use v6.d;
    
    use Scalar::Util:from<Perl5> <reftype>;
    
    my @a;
    say reftype @a; # ARRAY
    
    say reftype \(@a); # REF
    

    第一个之所以有效,是因为reftype 有一个带有单个参数的原型。 Perl5 中的大多数子例程都没有原型。即使这样做,方法调用也会忽略原型。


    在 Perl5 中,数组通常会展平为外部列表。

    use v5.12;
    
    my @a = 3,2,1;
    my @b = 5,4,@a;
    
    say for @b;
    # 5
    # 4
    # 3
    # 2
    # 1
    

    为了使调用 Perl5 代码更像 Perl5,数组被展平。

    use v6.d;
    use Inline::Perl5;
    
    my $p5 = Inline::Perl5.new;
    $p5.run( 'use v5.12; sub fubar { say for @_ }' );
    
    $p5.call( 'fubar', 1,2,3,[4,5] );
    # 1
    # 2
    # 3
    # 4
    # 5
    

    在 Perl6 中防止扁平化的一种方法是使其成为一个项目。

    use v6.d;
    
    my @a = 1,2,3;
    .say for @a;
    # 1
    # 2
    # 3
    .say for $@a;
    # [1,2,3]
    

    所以让我们在调用 Perl5 时尝试一下。

    use v6.d;
    use Inline::Perl5;
    
    my $p5 = Inline::Perl5.new;
    $p5.run( 'use v5.12; sub fubar { say for @_ }' );
    
    $p5.call( 'fubar', 1,2,3,$[4,5] );
    # 1
    # 2
    # 3
    # ARRAY(0x55cedda35300)
    
    $p5.call( 'fubar', 1,2,3,[4,5].item );
    # 1
    # 2
    # 3
    # ARRAY(0x55ceddbcfc38)
    
    $p5.call( 'fubar', 1,2,3,\[4,5] );
    # 1
    # 2
    # 3
    # REF(0x55ceddbcfb90)
    

    所以$(…).item 都可以防止数组在调用Perl5 代码时被展平,而不会像\(@) 那样被双重引用。

    【讨论】:

      猜你喜欢
      • 2019-06-26
      • 2018-09-11
      • 1970-01-01
      • 2019-06-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多