Author: ruoso Date: 2008-11-27 14:49:24 +0100 (Thu, 27 Nov 2008) New Revision: 24089
Modified: docs/Perl6/Spec/S07-iterators.pod Log: [spec] general S07 cleanup, I think that can be considered the first version. Most of the cleanup is related to accepting that it is runtime s responsability to instantiate the GenericLazyList when needed, and not the Iterator itself Modified: docs/Perl6/Spec/S07-iterators.pod =================================================================== --- docs/Perl6/Spec/S07-iterators.pod 2008-11-27 13:20:22 UTC (rev 24088) +++ docs/Perl6/Spec/S07-iterators.pod 2008-11-27 13:49:24 UTC (rev 24089) @@ -77,7 +77,7 @@ The feed operator is strictly lazy, meaning that no operation should be performed before the user requests any element from @a. That's how - my @a <== grep { ... } <== map { ... } <== grep { ... }, 1, 2, 3 + my @a <== grep { ... } <== map { ... } <== grep { ... } <== 1, 2, 3 is completely lazy, even if 1,2,3 is a fairly small known compact list. @@ -87,7 +87,7 @@ But it's important to notice that eagerness takes precedence over lazyness, meaning that - my @a = grep { ... } <== map { ... } <== grep { ... }, 1, 2, 3 + my @a = grep { ... } <== map { ... } <== grep { ... } <== 1, 2, 3 Will be eagerly evaluated, but that is still different from @@ -111,145 +111,52 @@ The iterator role represents the lazy access to a list, walking through a data structure (list, tree whatever), feeds (map, grep etc) -or and, each time it is called, will return one (or more) of the nodes -from the data structure. +or a stream (mostly for IO). Each time it is called, will return the +elements produced at that iteration. -When an iterator runs out of items, it will throw an exception. +It's important to realize that the iterator of a list can be accessed +by the .Iterator() method (but only the runtime will be calling that +most of the time), and the implemenation of each iterator is private +to the list and implementation specific. -The iterator role has the following methods: +This is a minimal API that should allow custom iterator +implemenations, but this spec should be expanded in the future to +provide additional API for batch-aware iterators. =head2 method prefix:<=> {...} -Returns something appropriate depending on the context: +Returns the items for that iteration. The grouping of elements +returned in each iteration is visible if this iterator is being used +to build a slice. While building a List, the items will be flattened. -=head2 method new(Laziness => $laziness, Context => $context) {...} +When it runs out of items, it will throw an exception. -Creates the iterator, with appropriate laziness defaults. +=head1 Auxiliary Implementations -=head2 method SetLaziness($laziness) {...} - -Set the Laziness - -=head2 method SetContext($context) {...} - -Set the Context (intended only for coercions, not user use) - -=head2 Iterator Summary - -=begin code - -role Iterator { - has $!laziness; - has $!context; - - # enforces item context - method FETCH() {...} - # returns a list - method List() {...} - # returns a slice - method Slice() {...} - # returns the capture of the next iteration - method prefix:<=> { - given $self.context { - when 'Item' { return self.FETCH() } # called in item context - when 'Slice' { return self.Slice() } # called in slice context - when * { return self.List() } # called in list context (or any other context) - } - } - # Creates a new iterator; can be called with no parameters, and chooses sensible defaults - method new(Laziness => $laziness, Context => $context) { - if(! $context) { - given want { - when :($) { $context = 'Item'; } # called in item context - when :(@@) { $context = 'Slice'; } # called in slice context - when * { $context = 'List'; } # called in list context (or any other context) - } - } - $self.context = $context; - self.SetLaziness($laziness); - } - method SetContext($context) { - $context ~~ /^(Item|List|Slice)$/) or die "Invalid context $context\n"; - $self.context = $context; - self.SetLaziness(); - } - method SetLaziness($laziness) { - if($laziness) { - $self.laziness = $laziness; - } else { - given $self.context { - when 'Item' { self.laziness = 'Mostly Lazy'; } - when * { self.laziness = 'Mostly Eager'; } - } - } - } -} - -=end code - -=head1 Default Implementations - Perl's built-ins require that a number of default iterators exist. -=head2 GenericIterator implementation +=head2 Generic Item Iterator -This is what is returned by default when an iterator is asked for, but no iterator type is known. +Operators like map requires one item at a time as input, therefore +they can use a generic item iterator to consolidate the access to the +input iterator, doing additional iterators when an empty capture is +returned and holding additional values if more than one item is +returned. -=head2 MapIterator implementation +=head2 Generic Lazy List -Example call: +The generic lazy list accepts an iterator as input, and consumes the +iterator as the elements of the list are accessed but flattening and +storing the already-evaluated elements. -# this is a good example of loose context information anyway... - other_something(| map { ... }, something()) +=head2 Generic Lazy Slice -When the map is initiated(???) this does the following steps in order: +The generic lazy slice accepts an iterator as input, and consumes the +iterator as the elements of the list are accessed but storing the +already-evaluated elements as a bi-dimensional list, where the first +dimension holds each iteration, and the second contains the return of +each iteration. -=over - -=item Coerce the return of something to Iterator (returning an Iterator object, which we can call $input_iterator) - -=item Coerce the iterator to item context (calls $input_iterator.SetContext() ) - -=item Create and return a new iterator that holds a reference to both the input iterator and to the map codeblock - (lets call this $map_iterator) - -=back - -When data is requested from the $map_iterator, the following steps are taken: - -=over - -=item map calls $map_iterator.prefix:<=> and gets the next item (even if that means many iterations or no new iterations in the input data) - -=item $map_iterator.prefix:<=> calls $map_iterator.code($item) (the number of arguments is defined by the .arity of the signature, and a call to $input_iterator.prefix:<=> is made to get each argument.) - -=item map returns the capture with no context applied (which means that it might contain several or no items) - -=back - -=begin code - -class MapIterator does Iterator { - has $.input_iterator; - has $.code; - method FETCH() { - return GenericItemIterator.new(input_iterator => self); - } - method List() { - return GenericLazyList.new(input_iterator => self); - } - method Slice() { - return GenericLazySlice.new(input_iterator => self); - } - method prefix:<=> { - return $.code.(=$.input_iterator); - } -} - -=end code - -=head2 GrepIterator implementation - =head1 Additions Please post errors and feedback to perl6-language. If you are making