什么算作单据的 "outer list"?
What counts as an "outer list" for a Slip?
docs for Slip 提到“Slip 是一个列表,它会自动扁平化为外部列表(或其他类似列表的容器或可迭代的)”。根据这个定义,这是完全有道理的:
dd my @a = 1, |(2, 3); # OUTPUT: «Array @a = [1, 2, 3]»
然而,令我惊讶的是:
dd my @b = do {@a[2] := |(3, 4); @a} # OUTPUT: «Array @b = [1, 2, slip(3, 4)]»
我原以为 slip(3, 4)
会变成 @b,而不是保持 slip
。 (也就是说,惊讶于 @a[2] := |(3, 4)
与 @a.splice(2, 1, [3, 4])
的语义不同。)
这里 list assignment 是否被视为特殊情况,具有与普通 Slip 不同的语义?还是 Slips/Lists/Arrays 的语义使得这一切在没有特殊外壳分配的情况下保持一致?
Slip 是一个列表 value,can 将其展平为外部序列。
所以下面生成了一个扁平化的列表。
1, |(2, 3)
它这样做是因为逗号 ,
.
如果您将该列表插入数组中的给定位置,您就是将该列表插入数组中的单个给定位置。
@a[0] = 1, |(2, 3); # [(1,2,3),]
如果插入一个 Slip,也会发生同样的事情,因为 Slip 只是 List 的一个子类。
@a[0] = |(2, 3); # [slip(2,3),]
事实上,单据几乎完全只是一个列表。这是 Rakudo 的代码。
# A Slip is a kind of List that is immediately incorporated into an iteration
# or another List. Other than that, it's a totally normal List.
my class Slip { # is List
# XXX this makes an empty Slip undefined?
multi method defined (Slip:D: --> Bool:D) { self.Bool }
multi method Slip(Slip:D:) { self }
method CALL-ME (+args) { args.Slip }
multi method raku(Slip:D: --> Str:D) {
nqp::if(
nqp::eqaddr(self,Empty),
'Empty',
nqp::stmts(
(my str $guts = callsame),
nqp::if(
nqp::eqat($guts,'$',0), # we're itemized
nqp::concat('$(slip',nqp::concat(nqp::substr($guts,1),')')),
nqp::concat('slip',$guts)
)
)
)
}
multi method List(Slip:D: --> List:D) {
my $list := nqp::create(List);
nqp::bindattr($list,List,'$!todo',nqp::getattr(self,List,'$!todo'))
if nqp::isconcrete(nqp::getattr(self,List,'$!todo'));
nqp::bindattr($list,List,'$!reified',nqp::getattr(self,List,'$!reified'))
if nqp::isconcrete(nqp::getattr(self,List,'$!reified'));
$list
}
}
这只会使 4 个功能起作用。
|().defined
这是定义了吗?
如果它包含元素是,否则不是。
(Empty
肯定是未定义的,但 |(,)
或 slip()
可能应该被定义。这个方法只是说两者都未定义。)
Slip((1,2))
将现有列表强制转换为单据。
Empty.raku
/ |(,).raku
打印值,使其可能被评估。
Empty
是空 Slip 的特定实例,在运行时有一些特殊处理。
|().List
获取列表而不是单据。
这需要在这里,因为 Slip 是 List 的子类,所以通常它只是 return 本身。
None 其中与将 Slip 展平为列表有关。
请注意,即使是顶部的评论也指出它只是一个普通列表。
如果您使用列表(ish,在本例中为 List
或 Range
)作为索引,您可以将其展平。
@a[2, ] = |(3,4); # [Any, Any, 3]
@a[2, 3] = |(3,4); # [Any, Any, 3, 4]
@a[2..3] = |(3,4); # [Any, Any, 3, 4]
通过使用列表索引,您告诉 Raku @a[…]
操作的结果是一个列表,而不是单个值。
这与右值是 Slip 无关。它与右值是 List 的子类有关。
更明确一点。
my $l-value := @a[2]; # contains the actual Scalar object in the array
my $r-value := |(3,4);
$l-value = $r-value;
这与您的代码所做的基本相同
@a[2] = |(3,4);
@a[2] =
是两个独立的操作。索引,然后赋值
@a[2]
return 是标量容器,然后 =
将右边的值赋给那个单一容器。
为了使 Slip 变平,赋值需要访问数组本身。它没有的东西。它只能访问单个标量容器。因此它将 Slip 插入到它所拥有的 Scalar 中。 (事实上,赋值并不知道标量甚至是数组中的一个成员。)
当你绑定时,你会做一些稍微不同的事情。问题是绑定应该比常规分配级别低。所以它更有可能只插入一个点而不是展平。
要让它做任何不同的事情,@a[2]
必须 return 一个知道如何将 Slip 压平成数组的代理。
如果您真的想这样做,请使用 splice
,因为它引用了数组。
my @a = 1, |(2, 3);
@a.splice: 2, 1, |(3,4);
同样,由于 Slip,这并不特别。
append 和 push 都很好用 slip:
my @a = 1, |(2, 3); #[1,2,3]
@a.append: |(3,4); #[1 2 3 3 4]
@a.push: |(3,4); #[1 2 3 3 4]
相比之下,没有滑动:
@a.append: (3,4); #[1 2 3 3 4]
@a.push: (3,4); #[1 2 3 (3 4)]
docs for Slip 提到“Slip 是一个列表,它会自动扁平化为外部列表(或其他类似列表的容器或可迭代的)”。根据这个定义,这是完全有道理的:
dd my @a = 1, |(2, 3); # OUTPUT: «Array @a = [1, 2, 3]»
然而,令我惊讶的是:
dd my @b = do {@a[2] := |(3, 4); @a} # OUTPUT: «Array @b = [1, 2, slip(3, 4)]»
我原以为 slip(3, 4)
会变成 @b,而不是保持 slip
。 (也就是说,惊讶于 @a[2] := |(3, 4)
与 @a.splice(2, 1, [3, 4])
的语义不同。)
这里 list assignment 是否被视为特殊情况,具有与普通 Slip 不同的语义?还是 Slips/Lists/Arrays 的语义使得这一切在没有特殊外壳分配的情况下保持一致?
Slip 是一个列表 value,can 将其展平为外部序列。
所以下面生成了一个扁平化的列表。
1, |(2, 3)
它这样做是因为逗号 ,
.
如果您将该列表插入数组中的给定位置,您就是将该列表插入数组中的单个给定位置。
@a[0] = 1, |(2, 3); # [(1,2,3),]
如果插入一个 Slip,也会发生同样的事情,因为 Slip 只是 List 的一个子类。
@a[0] = |(2, 3); # [slip(2,3),]
事实上,单据几乎完全只是一个列表。这是 Rakudo 的代码。
# A Slip is a kind of List that is immediately incorporated into an iteration
# or another List. Other than that, it's a totally normal List.
my class Slip { # is List
# XXX this makes an empty Slip undefined?
multi method defined (Slip:D: --> Bool:D) { self.Bool }
multi method Slip(Slip:D:) { self }
method CALL-ME (+args) { args.Slip }
multi method raku(Slip:D: --> Str:D) {
nqp::if(
nqp::eqaddr(self,Empty),
'Empty',
nqp::stmts(
(my str $guts = callsame),
nqp::if(
nqp::eqat($guts,'$',0), # we're itemized
nqp::concat('$(slip',nqp::concat(nqp::substr($guts,1),')')),
nqp::concat('slip',$guts)
)
)
)
}
multi method List(Slip:D: --> List:D) {
my $list := nqp::create(List);
nqp::bindattr($list,List,'$!todo',nqp::getattr(self,List,'$!todo'))
if nqp::isconcrete(nqp::getattr(self,List,'$!todo'));
nqp::bindattr($list,List,'$!reified',nqp::getattr(self,List,'$!reified'))
if nqp::isconcrete(nqp::getattr(self,List,'$!reified'));
$list
}
}
这只会使 4 个功能起作用。
|().defined
这是定义了吗?
如果它包含元素是,否则不是。
(Empty
肯定是未定义的,但|(,)
或slip()
可能应该被定义。这个方法只是说两者都未定义。)Slip((1,2))
将现有列表强制转换为单据。Empty.raku
/|(,).raku
打印值,使其可能被评估。
Empty
是空 Slip 的特定实例,在运行时有一些特殊处理。|().List
获取列表而不是单据。
这需要在这里,因为 Slip 是 List 的子类,所以通常它只是 return 本身。
None 其中与将 Slip 展平为列表有关。
请注意,即使是顶部的评论也指出它只是一个普通列表。
如果您使用列表(ish,在本例中为 List
或 Range
)作为索引,您可以将其展平。
@a[2, ] = |(3,4); # [Any, Any, 3]
@a[2, 3] = |(3,4); # [Any, Any, 3, 4]
@a[2..3] = |(3,4); # [Any, Any, 3, 4]
通过使用列表索引,您告诉 Raku @a[…]
操作的结果是一个列表,而不是单个值。
这与右值是 Slip 无关。它与右值是 List 的子类有关。
更明确一点。
my $l-value := @a[2]; # contains the actual Scalar object in the array
my $r-value := |(3,4);
$l-value = $r-value;
这与您的代码所做的基本相同
@a[2] = |(3,4);
@a[2] =
是两个独立的操作。索引,然后赋值
@a[2]
return 是标量容器,然后 =
将右边的值赋给那个单一容器。
为了使 Slip 变平,赋值需要访问数组本身。它没有的东西。它只能访问单个标量容器。因此它将 Slip 插入到它所拥有的 Scalar 中。 (事实上,赋值并不知道标量甚至是数组中的一个成员。)
当你绑定时,你会做一些稍微不同的事情。问题是绑定应该比常规分配级别低。所以它更有可能只插入一个点而不是展平。
要让它做任何不同的事情,@a[2]
必须 return 一个知道如何将 Slip 压平成数组的代理。
如果您真的想这样做,请使用 splice
,因为它引用了数组。
my @a = 1, |(2, 3);
@a.splice: 2, 1, |(3,4);
同样,由于 Slip,这并不特别。
append 和 push 都很好用 slip:
my @a = 1, |(2, 3); #[1,2,3]
@a.append: |(3,4); #[1 2 3 3 4]
@a.push: |(3,4); #[1 2 3 3 4]
相比之下,没有滑动:
@a.append: (3,4); #[1 2 3 3 4]
@a.push: (3,4); #[1 2 3 (3 4)]