Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I pass a sequence as a parameter in Perl 6?

Tags:

seq

raku

In Perl 6, I can iterate a literal sequence:

.say for 0 ... 3;

I can bind to a scalar and iterate that:

my $s := 0 ... 3;
.say for $s;

But I can't bind to a scalar, pass it as an argument, and then iterate that:

my $t := 0 ... 3;
show( $t );

sub show ( $seq ) { .say for $seq }

The subroutine gets a single element of type Seq, but it doesn't iterate it.

0
1
2
3
0
1
2
3
(0 1 2 3)

Does something in the process of preparing the parameter iterate through everything already?

like image 869
brian d foy Avatar asked Nov 21 '16 05:11

brian d foy


1 Answers

A value held in a Scalar container is not automatically iterated

While both $s and $seq are scalars (aka "variables"), $s is bound directly to a Seq value whereas your $seq is bound to an intermediary Scalar (note uppercase S) "container" that in turn contains the Seq. A value held in a Scalar container is not automatically iterated when used with features like for.


In more detail:

my $s := 0 ... 3;
.say for $s;

Because the my variable declaration uses the direct binding operator := for initialization, $s is directly bound to the single Seq value 0 ... 3.

This means the for statement sees a single Seq value, determines that it does the Iterable role, and flattens (iterates) it.

Now consider this:

my $s := 0 ... 3;
my $container = $s;
.say for $container;

Because the second my declaration uses the assignment operator = for initialization, the new variable $container is first bound to a new Scalar container which then "contains" whatever gets assigned.

In keeping with the language wide Slurpy Conventions (in particular: "An Iterable inside a Scalar container does not count"), a for statement does not iterate a value held in a Scalar container, so the .say for $container line only does one say.

A similar situation applies for your original show routine because variable parameter declarations are (semantically) containers by default.

One option is to instead add an is raw trait to your $seq parameter:

sub show ( $seq is raw ) { .say for $seq }

This prevents the usual automatic binding of $seq to a Scalar container (that in turn would contain the Seq value) as part of the call to show.

Another option is to let $seq be bound to a Scalar container but explicitly flatten (iterate) the $seq variable in the body of the show routine using a prefix |:

sub show ( $seq ) { .say for |$seq }
like image 147
raiph Avatar answered Dec 04 '22 05:12

raiph