Perl6:获取Perl5模块的数组引用

时间:2019-02-18 16:14:48

标签: perl6

我正在尝试使用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运算符的其他用途,请考虑使用:: =进行绑定   代替。如果打算捕获单个,则括号为(...)   变量。

所以我尝试了advice1:

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

出现错误

  

在-e行0处对write_row()的调用中不是数组引用。

advice2:

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

在-e行0处对write_row()的调用中不是数组引用。

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

给出相同的错误。

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

2 个答案:

答案 0 :(得分:8)

解决方案是写$@array而不是\@array

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

此答案的其余部分是有关使用已安装的外语适配器编写代码以及处理出现的任何问题的简要指南。我希望它可以作为一般资源,其答案远远超出了这个特定问题。

它从明显的问题“为什么$@foo?开始,讨论了如何成功使用外语适配器,并通过解释警告消息为何无用而结束。

为什么$@foo

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

也就是说,用户不需要了解P6的$功能,也不需要知道Inline::Perl5如何使用它来完成他们想要做的事情(编写P6代码)将数组引用从P5模块传递给函数)。

所以主要的答案是“为什么$@foo?”是您以这种方式编写它并且可以工作。 \ o /

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

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

  如果对Perl 6对象进行了容器化,则会自动进行

HASHARRAY引用:

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

(“容器化”一词指的是P6概念,lizmat在她的Containers in P6文章中为了解P5的人们很好地解释了。但是集装箱运输实际上与为什么 {{ 1}}表示在使用$@foo时在P5中使用数组引用。是的,它可以工作。不是,不必那样。)

为什么P6中的Inline::Perl5表示P5中的数组引用?

$@foo正确的原因不是因为P6语言或编译器认为是这样。

它是合适的 P6功能,但要做为正确的原因是,niner({{1的作者}})这样说。

niner为什么选择$@foo

大概是因为:

  • 对于新手来说很容易写;

  • 当有人认识P6时,这将是有意义的;

  • niner易于记录;

  • 很容易以高效的方式将其P6含义(Inline::Perl5中的$@foo转换为目标P5含义(P5数组引用)。

    < / li>

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

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

当Rakudo P6编译器在Scalar语句中看到Inline::Perl5时,它将隐式调用以前安装的称为:from<Perl5>的P6模块。

use安装marshaling代码,该代码自动将P6代码映射到P5代码或从P5代码映射出P6代码,以便P6和P5可以毫不费力地协同工作。

理想情况下,适配器只会完成它们的工作,而您无需考虑它们。但是:

  • 将P6中的Inline::Perl5映射到任何外语中的显而易见的事情是它们代表整数Inline::Perl5的值,但映射并不总是那么简单级别的数据结构,函数,引用等。有时编写P6代码可以完成的工作令人惊奇(您可以创建一个P6类,它是P5类的子类,完全可以像编写普通P6代码一样编写它!)但有时您必须遵循规则(在这种情况下,如何将P6数组传递给P5作为数组引用)。请参阅下面的适配器文档部分。

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

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

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

亲爱的读者以及我们所有人中,一种更快地接近理想的方法是通过现有适配器使用外部模块,并在某些特定功能似乎无法正常工作时编写SO问题和文件问题。谢谢@ con,niner,以及其他实现这一目标的人。

适配器文档

要确定要使用通过42使用的外语模块应该编写哪些P6代码,唯一的方法是:

  • 阅读外语模块的文档以查看期望的内容。然后

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

在这种情况下,我们正在谈论使用42,适配器是:from<...>。目前其文档为its github project repo README。因此,要了解要为P5和P5模块提供他们所期望的内容,请阅读该文档。

每个适配器都有自己的文档;请参阅modules.perl6.org上的链接列表。

警告和错误

如果在P6中使用外语模块时出现任何问题(当直接使用该外语使用相同代码时也没有错),

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

  • 如果收到警告或错误消息,请确保参考适配器的文档及其问题队列,以了解它是否对该特定消息有所帮助;

  • 如果您认为使用外语模块在P6中工作(或不工作)时存在错误(直接在该外语中使用时效果很好),请参阅适配器的发布队列。例如,如果您使用的是:from<Perl5>,请参阅Inline::Perl5's issue queue。如果您决定发布某些内容,则可以在不确定的情况下在此处发布,如果您不确定,则在适配器的发布队列中发布。

由于P6语言和编译器不知道映射正在进行中,因此警告和错误消息在学习使用涉及以下规则(例如{{1 }}的规则。

对于P5问题,P6可能会加剧这种情况,因为P6试图对编写P6代码的P5编码人员有所帮助,并且在使用Inline::Perl5时尝试回火。问题中的示例是一个很好的示例:

:from<Perl5>

P6认为您可能习惯于使用前缀$@foo来编写数组引用。它认为您可能不知道不需要在P6中写斜杠。并没有意识到您要坚持通过P Inline::Perl5获取P5可以理解的数组引用。

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

P6认为您正在尝试执行P5中通常用\完成的操作,不是因为您想使用P5,而是因为您知道P5,所以想要在P6中完成某些事情 P5 ,并希望能使用完全相同的语法。

(顺便说一句,Inline::Perl5的建议肯定无济于事-因为For other uses of Perl 5's ref operator consider binding with ::= instead. 尚未实施!)

\

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

应该将其建议解释为建议您写::=而不是::=来创建包含Parenthesize as (...) if you intended a capture of a single variable. 的{​​{1}}。

它警告使用\(@foo)来表示\@foo正是因为P5开发人员可能会写它以为会创建数组引用。

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

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

答案 1 :(得分:4)

::=是一个中缀运算符,因此您需要在其左侧添加一些内容。如果使用了它,您会发现它尚未实现。但这没关系,因为它仍然无济于事。

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


在Perl5中,\创建一个引用。在Perl6中,实际上没有这样的东西。

use v5.12;

my @a;
my $a = \@a;
say ref $a; # ARRAY
say ref \$a; # REF

在Perl6中,\用于创建捕获。

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代码时使数组变平而不会像\(@)那样被重复引用。