Skip Menu |
Report information
Id: 127121
Status: open
Priority: 0/
Queue: perl6

Owner: Nobody
Requestors: jules [at] jules.uk
Cc:
AdminCc:

Severity: (no value)
Tag: Bug
Platform: (no value)
Patch Status: (no value)
VM: (no value)



Subject: [BUG] flat can't flatten arrays, but can flatten lists
Download (untitled) / with headers
text/plain 508b
flat has no effect on arrays, but works fine on lists: Show quoted text
> ((1,2),3).flat.perl
(1, 2, 3).Seq <== Correct Show quoted text
> [[1,2],3].flat.perl
($[1, 2], 3).Seq <== Failed Show quoted text
> [(1,2),3].flat.perl
($(1, 2), 3).Seq <== Failed Show quoted text
> ([1,2],3).flat.perl
(1, 2, 3).Seq <== Correct Show quoted text
> [(1,2),3].List.flat.perl
(1, 2, 3).Seq <== Coerced to a list before flat Running on OS X: $ perl6 --version This is Rakudo version 2015.12 built on MoarVM version 2015.12 implementing Perl 6.c. Many thanks! -- Jules@Jules.uk
Download (untitled) / with headers
text/plain 1.3k
This is actually a fallout of the interaction of two intentional design features: 1) Arrays itemize (wrap in Scalar) everything assigned to them and 2) Itemization (Scalars) protect against flattenning Which makes it reasonable to ask, why does Array have a ".flat" method if it cannot do anything? However, if you force the array not to itemize using a direct bind (which bypasses the assignment itemization, and is generally discouraged) you should be able to observe flattening in Arrays. Indeed this actually does seem to be broken, $ perl6 -e ' Show quoted text
> my @a = (1,23,4); > @a[1] := (2,3); > @a[1].VAR.WHAT.say; > @a.flat.say;'
(List) (1 (2 3) 4) Now, if running an Array through an iterator shold return the Scalars, rather than the values, this will remain a design wart even after fixing the above. There have been several users on IRC lately running into this in one form or another, many because some packages are electing to return nested arrays rather than nested lists even when their return values are not useful as mutables. If an array should de-itemize during iteration, then Array.flat would behave intuitively, but that could have lots of other impacts. If Array.flat were special-cased, that would sweep the wart slightly under a rug until someone who wants to selectively preserve structure finds that inconsistent.
From: Jules Field <Jules [...] Jules.uk>
Date: Sun, 3 Jan 2016 09:44:15 +0000
To: perl6-bugs-followup [...] perl.org
Subject: Re: [perl #127121] [BUG] flat can't flatten arrays, but can flatten lists
Download (untitled) / with headers
text/plain 2.5k
Brian, The snag is this: Show quoted text
> my @a = (1, (2,3), 4);
[1 (2 3) 4] I asked for a List, but got given an Array. So I can do this: Show quoted text
> (1, (2,3), 4).flat;
(1 2 3 4) but not this: Show quoted text
> @a.flat;
(1 (2 3) 4) And now @a.flat is a list. But if I assign the result to @b then this happens: Show quoted text
> my @b = @a.flat;
[1 (2 3) 4] Now it's turned into an Array again! How can it be right that if I split 1 line of code into 2 by creating an intermediary variable, the code behaves totally differently? If it's intentional, then what am I doing wrong in my trivial example above? Many thanks for your help! Cheers, Jules. On 03/01/2016 02:23, Brian S. Julin via RT wrote: Show quoted text
> This is actually a fallout of the interaction of two intentional design features: > > 1) Arrays itemize (wrap in Scalar) everything assigned to them > and > 2) Itemization (Scalars) protect against flattenning > > Which makes it reasonable to ask, why does Array have a ".flat" method if it > cannot do anything? However, if you force the array not to itemize using a > direct bind (which bypasses the assignment itemization, and is generally > discouraged) you should be able to observe flattening in Arrays. > > Indeed this actually does seem to be broken, > > $ perl6 -e '
>> my @a = (1,23,4); >> @a[1] := (2,3); >> @a[1].VAR.WHAT.say; >> @a.flat.say;'
> (List) > (1 (2 3) 4) > > Now, if running an Array through an iterator shold return the Scalars, rather > than the values, this will remain a design wart even after fixing the above. > There have been several users on IRC lately running into this in one form or > another, many because some packages are electing to return nested arrays rather > than nested lists even when their return values are not useful as mutables. > > If an array should de-itemize during iteration, then Array.flat would behave > intuitively, but that could have lots of other impacts. If Array.flat were > special-cased, that would sweep the wart slightly under a rug until someone > who wants to selectively preserve structure finds that inconsistent. > > >
Jules -- Jules@Jules.UK Twitter: @JulesFM 'Ever since the dawn of civilization, people have craved for an understanding of the underlying order of the world: why it is as it is, and why it exists at all. But even if we do find a complete theory of everything, it is just a set of rules and equations. What is it that breathes fire into the equations, and makes a universe for them to describe?' - Stephen Hawking -- This message has been scanned for viruses and dangerous content by MailScanner, and is believed to be clean.
Date: Mon, 4 Jan 2016 15:42:50 +0100
Subject: Re: [perl #127121] [BUG] flat can't flatten arrays, but can flatten lists
To: "Juerd Waalboer (via RT)" <perl6-bugs-followup [...] perl.org>
From: Elizabeth Mattijsen <liz [...] dijkmat.nl>
Download (untitled) / with headers
text/plain 1.4k
Show quoted text
> On 03 Jan 2016, at 10:44, Jules Field <Jules@Jules.uk> wrote: > The snag is this:
> > my @a = (1, (2,3), 4);
> [1 (2 3) 4] > > I asked for a List, but got given an Array. So I can do this:
If like that, you really have asked for an Array (@a) to be assigned with the values of a List (1, (2,3), 4). If you want @a to be a List, you need to *bind* it to the List. $ 6 'my @a = (1, (2,3), 4); say @a.WHAT' (Array) $ 6 'my @a := (1, (2,3), 4); say @a.WHAT' (List) Show quoted text
> > (1, (2,3), 4).flat;
> (1 2 3 4) > > but not this:
> > @a.flat;
> (1 (2 3) 4)
.flat returns a Seq $ 6 'my @a := (1, (2,3), 4); say @a.flat.WHAT' (Seq) Show quoted text
> And now @a.flat is a list. But if I assign the result to @b then this happens:
> > my @b = @a.flat;
> [1 (2 3) 4] > > Now it's turned into an Array again!
Again, you need to bind if you want @b to be a List. Because you can’t bind a Seq, it needs to be coerced to a List: $ 6 'my @a = (1, (2,3), 4); my @b := @a.flat.list; say @b.WHAT' (List) Show quoted text
> How can it be right that if I split 1 line of code into 2 by creating an intermediary variable, the code behaves totally differently? > If it's intentional, then what am I doing wrong in my trivial example above?
Because the @ sigil forces an Array by default. You don’t have to use an @ sigil though: $ 6 'my $a = (1, (2,3), 4); my $b = $a.flat.list; say $a.WHAT; say $b.WHAT' (List) (List) Show quoted text
> Many thanks for your help!
Hope this helps… Liz
Download (untitled) / with headers
text/plain 681b
Liz, IMO the real problem is that, per documentation [ method list: "Interprets the invocant as a list, and returns that List." ], we expect that @foo.list.WHAT === List, ie @foo.list.^name eq 'List' But right now rakudo don't agree: $ perl6 -e 'my ($a,%a,@a); say .WHAT, .list.WHAT === List for $a,%a,@a,$(1,2),Nil,Any,1,"foo",{},[]' (Any)True (Hash)True (Array)False (List)True NilTrue (Any)True (Int)True (Str)True (Hash)True (Array)False I can't found that tested in roast, so where is specified that .list applied to an Array should be a nop? But with an explicit .List: $ perl6 -e 'my ($a,%a,@a); say .List.WHAT === List for $a,%a,@a,[]' True True True True Regards.
RT-Send-CC: liz [...] dijkmat.nl
Download (untitled) / with headers
text/plain 601b
Digging deeper I finally found some answers. Array.flat was designed and implemented for flattening shaped arrays: $ perl6 -e "my @a[2;2] = [ 'a', 1 ],[ 'b', 2 ]; my @b = @a.flat; .say for @a,@b" [[a 1] [b 2]] [a 1 b 2] So, @foo.flat seems to be a nop iff @foo.shape.elems == 1, as a degenerated case. Iterator.flat and Array.flat are orthogonal: $ perl6 -e "my @a[2;2] = [ 'a', (3,4) ],[ 'b', (5,6) ]; .say for @a, @a.flat, @a.List.flat;" [[a (3 4)] [b (5 6)]] (a (3 4) b (5 6)) (a 3 4 b 5 6) To avoid the confusion doc/Type/Array needs to document shaped arrays and its .flat method. Regards.


This service is sponsored and maintained by Best Practical Solutions and runs on Perl.org infrastructure.

For issues related to this RT instance (aka "perlbug"), please contact perlbug-admin at perl.org