On Sat, Dec 04, 2004 at 08:03:53PM +0300, Alexey Trofimenko wrote:
: hm.. consider that:
: 
: perl5:
:    open $fh, 'file';
:    $first_line = <$fh>;
:    @remaining = <$fh>;
: 
: perl6:
:    $fh = open 'file';
:    $first_line = $fh();
:    @remaining = $fh();
: 
: I thought about parallels between arrays and iterators,  and realized that  
: they aren't very close to each other:
: iterators are much closer to subroutines. And moreover, in perl5 they ARE  
: subroutines. In abstract, arrays are things with plenty of access methods  
: and iterator is the thing with a single action: "one more result, please".  
: and that simplicity IS a power.
: so why not just CALL our iterator?

Why not indeed.

: of course, that analogy isn't going to work for "true" functions, which  
: returns the same all the time, for some given set of arguments.

Oh, well, we pissed off the mathematicians long ago.  :-)

At least we had the sense to call them subroutines instead of functions.
Of course, that also upset the mathematicians, who wanted to call them
functions anyway.  Go figure.

: so, of course, arrays and iterators should be interchangeable, but it  
: could be kin to an autoconversion. And we for sure have no need to convert  
: iterator to array so that we should convert it back again later, for  
: C<for> etc. (as some people here already stated)

Yes, that seems right.  An array can (and often does) provide a
"view" of the results of an iterator (which may in fact be a Lazy
list of iterators), but that doesn't mean that all iterators have to
be viewed through an array.

: ok, "structured" part of my brain is over.. now,
: random thoughts:
: 
:  $fh(:chomp)

Yes, but in general I think an autochomper layer should be applied
to the handle/iterator at open/construction time, not at evaluation time.

: for &$fh {...}

No, &foo doesn't do anything in Perl 6 except return a function pointer.
Have to use parens.

    for &$fh() {...}

in which case you might as well drop the &.

: for &$fh.assuming(:chomp) {...}

Same issue, all you're doing is iterating over a single value which is
a curried function pointer.  Have to say

    for $fh.assuming(:chomp)() {...}

But note that a naive implementation of that is going to recurry the
iterator every time through.  Again, much cleaner to do it outside the
loop rather than relying on an optimizer that might let you down if
it can't intuit the purity of the call.

Interestingly, adding a layer to a filehandle is very much like a curry.

: # what about making &foo( :bar ) the same as
: #  &foo.assuming( :bar) ? ah, that not gonna work.. but I
: # think that feature definitely wants something more short
: # than .assuming; maybe even some special syntactic honey.
: # because it's  fun(ny|ctional)

We made it long on purpose for readability.  You can always use a macro
to obfuscate it.  What we're *not* going to do is autocurry missing
parameters like Haskell.  That just screws up all the compiler's
expectations on return types.  If I forget to supply an argument, I
want an error, not a function pointer.  I can add in the .assuming
myself when I decide I need it.  All autocurrying does is sweep the
dirt under the carpet for someone else to deal with.

: class Foo {
:   has $.counter;
:   # multi postcircumfix:<( )> makes me sick :(

Not sure it needs to be multi.  Generally a reference tells you exactly
who you're dispatching to.

:   method bar is default {
:      $.counter++;
:   }
: }
: 
: # emulating   10...
: $a = new Foo :counter(10);
: say $a.bar;
: say $a();

Probably want to handle list context as well.

: # other thingies:
: 
:  sub foo { ... };
:  @array = @&foo # all the results of foo, lazily.

Don't see the need for that when

    @array := foo()

does laziness implicitly already.  Maybe even

    @array = foo()

maintains laziness if it sees an infinite iterator in the return
value of foo().  Or maybe it blows up and tells you to use ":="
to avoid trying to make a copy.  That's probably cleaner.

: maybe  &@array and @array()  could make a sense too:
: 
:   $fibonacci = {
:      state ($a, $b) = (1,1);
:      while $b <100 {
:        ($a,$b) = ($b, $b+$a);
:        yield $a
:      }
:   }
: 
: (ah, that isn't very short and impressive.. I need to study a  course of  
: "Design of Short and Impressive Examples", by  Damian or Mark-Jason,  
: maybe.)
: 
:   for @$fibonacci ... # or...
:   for &$fibonacci ... # or...
:   for $fibonacci ...
: 
: interesting problem: how could we iterate through a list of iterators, one  
: by one, without flattening 'em?

By declaring it to be a Lazy list, whereupon the array view of the
list is the internal list of iterators (and any intermediate existing
scalar values).

: and the very last  and most important problem: I have no idea how we could  
: signal an end of sequence.

Just stop yielding things.  For an ordinary sub, return something finite.
For a gather, exit the gather.  In general, stop putting new iterators
or values on the Lazy you're building.

: something_special?

You just run into the end of the Lazy when you try to .pull from it.
An undef is sufficiently special.  Exceptions should not be used for
something so mundane as running out fo values.

: or maybe even perform some self-destructing action?
: 
: {
:    undef &whatever_we_have_at_this_moment_standing_for_current_function
:       if end_condition
: }

If that's necessary to keep the Lazy from blocking when it runs out
of values.  Just like an ordinary array, a Lazy has to be aware of
when it is out of values, and when it should call into some meta-Lazy
for more iterator values.  And I suppose that meta-Lazy could in
turn have a meta-meta-Lazy, which could have a meta-meta-meta-Lazy,
and now my brane hurts.

Larry

Reply via email to