Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

flat can't flatten arrays, but can flatten lists #4979

Open
p6rt opened this issue Jan 2, 2016 · 7 comments
Open

flat can't flatten arrays, but can flatten lists #4979

p6rt opened this issue Jan 2, 2016 · 7 comments
Labels

Comments

@p6rt
Copy link

p6rt commented Jan 2, 2016

Migrated from rt.perl.org#127121 (status was 'open')

Searchable as RT127121$

@p6rt
Copy link
Author

p6rt commented Jan 2, 2016

From jules@jules.uk

flat has no effect on arrays, but works fine on lists​:

((1,2),3).flat.perl
(1, 2, 3).Seq <== Correct

[[1,2],3].flat.perl
($[1, 2], 3).Seq <== Failed

[(1,2),3].flat.perl
($(1, 2), 3).Seq <== Failed

([1,2],3).flat.perl
(1, 2, 3).Seq <== Correct

[(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

@p6rt
Copy link
Author

p6rt commented Jan 3, 2016

From @skids

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.

@p6rt
Copy link
Author

p6rt commented Jan 3, 2016

The RT System itself - Status changed from 'new' to 'open'

@p6rt
Copy link
Author

p6rt commented Jan 4, 2016

From jules@jules.uk

Brian,

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​:

(1, (2,3), 4).flat;
(1 2 3 4)

but not this​:

@​a.flat;
(1 (2 3) 4)

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!

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​:

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.

@p6rt
Copy link
Author

p6rt commented Jan 4, 2016

From @lizmat

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)

(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)

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)

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)

Many thanks for your help!

Hope this helps…

Liz

@p6rt
Copy link
Author

p6rt commented Jan 7, 2016

From @salortiz

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.

@p6rt
Copy link
Author

p6rt commented Jan 11, 2016

From @salortiz

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.

@p6rt p6rt added the Bug label Jan 5, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant