Re: Multi-d array transforms (was Re: Array rotate)

2009-06-13 Thread Matthew Walton
On Sat, Jun 13, 2009 at 1:08 AM, Larry Wallla...@wall.org wrote:
 Nevertheless, for any major methods borrowed from Perl 6, I'm not
 inclined to change them that drastically.  Much more likely to
 define them as sugar for the more general list operators:

    .push       means   .=append
    .unshift    means   .=prepend
    .splice     means   .=impend        :-)

 or some such.

That makes sense to me. I'd very much like it if the fundamental
methods on most data types were non-mutating - string manipulation,
list munging etc. Along with having lazy lists, that gives us a good
dose of tricks from the functional world we can do, and with .= and
(hopefully) some clever bits in the compiler which can handle it
effectively (as in performance-wise), it's no hassle to convert any
non-mutator to a mutator. Syntactic sugar for really common mutating
cases, as in other methods which do 'the same thing but mutated' is of
course fine (particularly when they have sensible/familiar names,
which implies to my mind that the operation makes sense).

Although some things may be able to be implemented far more
efficiently if they know that they're being called with infix:.= and
not with infix:..

method munge($self is ro:) { } # infix:. case
method mung($self is rw:) { } # infix:.= case

?

Marginally inspired by C++ const methods. Of course, a potential
problem here is that they might want different return types as well -
but maybe our multis are fine with that, and maybe this is just some
crazy dream caused by waking up too early on a Saturday morning and
thinking about Perl before breakfast.

Matthew


Re: Multi-d array transforms (was Re: Array rotate)

2009-06-13 Thread Daniel Carrera

Larry Wall wrote:

Nevertheless, for any major methods borrowed from Perl 6, I'm not
inclined to change them that drastically.  Much more likely to
define them as sugar for the more general list operators:

.push   means   .=append
.unshiftmeans   .=prepend
.splice means   .=impend:-)

or some such.


I like those. I feel similar to Matt W. I kind of like .push and 
.unshift the way they are (probably just habit) But I can appreciate 
that non-mutating alternatives might open a new class of algorithms from 
the functional world.


Daniel.


Re: Multi-d array transforms (was Re: Array rotate)

2009-06-13 Thread Jon Lang
On Fri, Jun 12, 2009 at 11:23 PM, Matthew
Waltonmatt...@matthew-walton.co.uk wrote:
 Although some things may be able to be implemented far more
 efficiently if they know that they're being called with infix:.= and
 not with infix:..

Last I checked, Perl 6 had some types that are mutating and others
that aren't (e.g., List and Array, I think).  An additional benefit of
setting up the primitive methods as non-mutating is that you
increase the amount of functionality shared by the two: if all
mutating methods are syntactic sugar for non-mutating counterparts,
then non-mutating types will be able to do everything that their
mutating brethren can do (except mutate, of course).  E.g., a List can
push, unshift, splice, etc; an Array can append, perpend, impend, etc.

And if you want to do purely functional programming, you can do so by
restricting yourself to the use of non-mutating types and staying away
from those methods that have side effects (which should [i]also[/i] be
easily identifiable).  Indeed, this same notion of ensuring that pure
functional versions of mutating methods exist should also apply to
methods with side effects: as much as possible, if a method is
designed to perform a calculation and to produce a side effect, there
should also be an equivalent method that merely performs the
calculation.  Even better would be to segregate the methods that
produce side effects from the methods that perform calculations.

Am I making sense?

-- 
Jonathan Dataweaver Lang


Re: Array rotate

2009-06-13 Thread John M. Dlugosz

Jon Lang dataweaver-at-gmail.com |Perl 6| wrote:

On Fri, Jun 12, 2009 at 10:02 AM, yarynot@gmail.com wrote:
  

I am tickled pink to see an Array rotate method in the settings spec
S032, as I was thinking of writing up a little discussion on the very
topic.

Has there been discussion on using array rotate on multi-dimensional
arrays? Being able to pass in a vector as the amount to rotate would
be useful.



With a multi-dimensional array, a number of transforms can be considered:

* you can rearrange the elements along a given dimension (e.g., rotate
and reverse).
* you can rearrange the dimensions themselves (e.g., transpose).

  

A short time ago, something similar came up.

I think the built-in's should stay simple, and a module (or several 
different ones) can exist to do comprehensive features for 
multi-dimensional arrays.  Designing that is really a separate project 
in itself, and it may shake out with use.


So keep it out of the core spec.

--John



Re: Multi-d array transforms (was Re: Array rotate)

2009-06-13 Thread John M. Dlugosz

Larry Wall larry-at-wall.org |Perl 6| wrote:

We also need to consider the dimension of referentiality.  I can see
three levels here.  Given

@a.mung

the .mung could return

A) a modified @a (treat @a as mutable)
B) a new array (treat @a as immutable)
C) a remapped array whose elements refer back to @a's elements

Currently .rotate is defined as A, but I could easily switch it to B,
so you'd have to write

@a.=rotate;

  
Having some operation XX return a new object and using =.XX do it in 
place would be consistent with the way other things are shaping up.  
But people expect push to work like they are used to, and the exported 
push, called as a sub not as a method, would be copying. 


In void context it could give an error.

   push @a, $x;# what's the point?

if we had a general way to decorate the sub definition to day must not 
use in void context.


As expressed already in the synopses, the function called for 
@a.=push($x); can be written specially to handle the in-place case, 
rather than have to assign back after copying like the auto-generated 
case would.  (What exactly define a self.push operator means needs to 
be clarified in S12.  Is that not the normal sub syntax?)  In other 
words, defining self.push would be the implementation that Perl 5 push 
is now.




to rotate in place.  If we did that, then we could conceivably set
things up with more PDLish C semantics so that

@a .= mung  # A semantics
@b  = @a.mung   # B semantics
@b := @a.mung   # C semantics

  
That third one would be rather inefficient.  The returned array would 
need to be set up as an array of binding proxies, if the original wasn't 
set up as an array of item containers, just in case it gets bound to 
something (or used as part of a larger expression) rather than assigned.


I'm looking at this general issue right now (musing over it the last 
week actually) and although it's nowhere near done yet, you can see 
Figure 1 at http://www.dlugosz.com/Perl6/web/container-lvalues.html 
and the text that is taking shape around it.





This implies, however, that the copy semantics of = are sufficiently
clever to snapshot all the referenced values of @a before clobbering
@a in the case of either:

@a .= mung
@a = @a.mung

But list assignment really ought to be doing that in any case.

  
Wow.  The overarching logic for list assignment would have to compare 
the containers and the arguments in the capture before doing the list 
assignment to each container, in order to avoid cloning all the 
containers on the right first in the general case.  It can't just copy 
values out because they may contain iterators or be lazy or be infinite.


--John



Re: Array Dimensionality (Was: Re: Multi-d array transforms (was Re: Array rotate))

2009-06-13 Thread John M. Dlugosz

Larry Wall larry-at-wall.org |Perl 6| wrote:

Alternately, we leave @@ (or @%) meaning ¢ and instead let some
other syntax take over the pay attention to the capture's structure
semantics from @@.  Maybe it's another use for the zen slice:

  



pay attention to the capture's structure is a can of worms.  As things 
stand now in the Synopses, you get a lot of empty extra wrappers around 
things.  You don't want to keep that exact!  When you are not doing 
full-blown flattening, which levels in the morphology are extra due to 
passing though functions or grouping parens, and which are intended to 
be part of the final structure?  Since the crazy stuff inside the 
capture is usually invisible, people will have a hard time using that 
correctly.


(A literal reading of the synopses now gives us the morphology 
illustrated at http://www.dlugosz.com/Perl6/web/med-loop.html, and I 
hope to remove _some_ of those extra wrappings through refinement of the 
rules when I get around to studying that in detail.)


My thoughts at this point is that slice context needs to *know* it is 
being rolled up into a final result that is a 2-dim array.  The rules 
for that will strip out extra wrappers except where it really is 
significant, designed through use cases of seeing what common constructs 
actually produce.


A shaped array knows what needs to be poured into it, so the RHS can be 
flattened.  The single-dim array is just a special case of that; it 
generalizes to higher dimensions just fine, as seen in languages like APL.


A smart shaped assignment, to handle containers with * in other than the 
highest position, can be supplied as part of a multi-dim array Module, 
designed separately along with a coherent set of features such as 
general vector-driven transposes etc.


--John



Re: Array Dimensionality (Was: Re: Multi-d array transforms (was Re: Array rotate))

2009-06-13 Thread John M. Dlugosz

Daniel Ruoso daniel-at-ruoso.com |Perl 6| wrote:

So, how do I deal with a multidim array? Well, TIMTOWTDI...

 my @a = 1,[2,[3,4]];
 say @a[1][1][1];
 say @a[1;1;1]; # I'm not sure this is correct

  
I think that it should be.  That is, multi-dim subscript is always the 
same as chained subscripts, regardless of whether the morphology is an 
array stored as an element, or a multi-dim container, or any mixture of 
that as you drill through them.


I've not written out a full formalism yet, but I've thought about it.
The multi-dim subscript would return a sub-array if there were fewer 
parameters than dimensions, an element if exact match, and recursively 
apply the remaining subscripts to the element if too many.




Or.. (I'm using the proposed capture sigil here, which has '@%a' as its
expanded form)

 my ¢a = 1,(2,(3,4);
 say ¢a[1][1][1];
 say ¢a[1;1;1];

I think that makes the semantics of the API more clear...

daniel


  

The plain Array would work too, in the nested morphology:

   my @a = 1,[2,[3,4]];

@a has 2 elements, the second of which is type Array.

   say @a[1][1][1];

naturally.

   say @a[1;1;1];

means the same thing, intentionally.

   say @a[1][1;1];
   say @a[1;1][1];

ditto.

--John




Re: Multi-d array transforms (was Re: Array rotate)

2009-06-13 Thread John M. Dlugosz

Daniel Carrera daniel.carrera-at-theingots.org |Perl 6| wrote:
In addition, the current @a.shift is useful because it returns the 
element that was removed from the array, so you can do something with it:



The change to the library synopses was checked in before you posted 
that, if I recall the delta correctly.


But you bring up a point:  that is indeed the common idiom from Perl 5. 


That brings up the following radical idea:

Have no method named shift at all.  Shift etc. will be a non-member sub 
brought in through


   use legacy;

and designed to work just like Perl 5, for that express purpose.  The P6 
way of doing it would be to not do that: use iterators rather than 
destructivly going through the array, or use decomposition to do things 
in a more functional way, or use the more general syntax to delete one 
element from the beginning, in-place or copy as indicated.


--John



Re: Multi-d array transforms (was Re: Array rotate)

2009-06-13 Thread Larry Wall
On Sat, Jun 13, 2009 at 02:49:10PM -0500, John M. Dlugosz wrote:
 Wow.  The overarching logic for list assignment would have to compare  
 the containers and the arguments in the capture before doing the list  
 assignment to each container, in order to avoid cloning all the  
 containers on the right first in the general case.  It can't just copy  
 values out because they may contain iterators or be lazy or be infinite.

Well, that's not really a problem, as long as the same semantics
are preserved.  All you need to do is cut loose the contents of the
container completely to the mercy of GC, build a new one with the
appropriate structure, then copy values in from the assignment's RHS.
The only reason Perl 5 couldn't do it this way is that the idiot who
wrote it prematurely optimized values on the stack so that they didn't
need to be reference counted. :)

Larry


Re: Multi-d array transforms (was Re: Array rotate)

2009-06-13 Thread John M. Dlugosz

Larry Wall larry-at-wall.org |Perl 6| wrote:

On Sat, Jun 13, 2009 at 02:49:10PM -0500, John M. Dlugosz wrote:
  
Wow.  The overarching logic for list assignment would have to compare  
the containers and the arguments in the capture before doing the list  
assignment to each container, in order to avoid cloning all the  
containers on the right first in the general case.  It can't just copy  
values out because they may contain iterators or be lazy or be infinite.



Well, that's not really a problem, as long as the same semantics
are preserved.  All you need to do is cut loose the contents of the
container completely to the mercy of GC, build a new one with the
appropriate structure, then copy values in from the assignment's RHS.
The only reason Perl 5 couldn't do it this way is that the idiot who
wrote it prematurely optimized values on the stack so that they didn't
need to be reference counted. :)

Larry

  
I agree, if the contents include the iterators and code blocks and 
whatnot that make up the concrete types of the things on the right.  But 
if it's not a built-in standard type, it might require a call to the 
general shallow-copy clone of the object.


  my @A is CustomContainer;
  my @B[7];  # fixed size
  ...
  @B,@A,@C = @A,@B;

The compiler doesn't know how to juggle the internals of @A because it 
is not a standard type.  This needs to become:


   my @temp1 = @A.clone;
   my @temp2 = @B.clone;
   @B,@A,@C = @temp1,@temp2;

and assume that the compiler might optimize the case with @B through 
innate knowledge, and possibly inline and optimize over the calls for @A.




Premature optimization is the root of all evil.

But... design the semantics so there is some hope of optimization.  That 
might entail designing in some features of Positional that will be used 
by this construct, as more efficient than just calling .clone().


OTOH, machines are a million times faster than what Perl 4 originally 
ran on.