Author: ruoso
Date: 2008-11-27 14:20:22 +0100 (Thu, 27 Nov 2008)
New Revision: 24088

Added:
   docs/Perl6/Spec/S07-iterators.pod
Log:
[spec] Adding the first sketches on S07, thanks to wayland76++

Added: docs/Perl6/Spec/S07-iterators.pod
===================================================================
--- docs/Perl6/Spec/S07-iterators.pod                           (rev 0)
+++ docs/Perl6/Spec/S07-iterators.pod   2008-11-27 13:20:22 UTC (rev 24088)
@@ -0,0 +1,256 @@
+=encoding utf8
+
+=head1 Title
+
+Synopsis 7: Iterators and Laziness
+
+=head1 Version
+
+ Maintainer:    ???
+ Contributions: Tim Nelson <[EMAIL PROTECTED]>
+                Daniel Ruoso <[EMAIL PROTECTED]>
+ Date:          27 Nov 2008
+ Last Modified: 27 Nov 2008
+ Version:       1
+
+=head1 Laziness and Eagerness
+
+As we all know, one of the primary virtues of the Perl programmer is
+laziness.  This is also one of the virtues of Perl itself.  However,
+Perl knows better than to succumb to false laziness, and so is eager
+sometimes, and lazy others.  Perl defines 4 levels of laziness for
+Iterators:
+
+=over
+
+=item Strictly Lazy
+
+Does not evaluate anything unless explictly required by the user,
+including not traversing non-lazy objects.
+
+=item Mostly Lazy
+
+Try to obtain available items without causing eager evaluation of
+other lazy objects.
+
+=item Mostly Eager
+
+Obtain all items, but does not try to eagerly evaluate when known to
+be infinite.
+
+=item Strictly Eager
+
+Obtain all items, fail in data structures known to be infinite.
+
+=back
+
+It's important to realize that the responsability of determining the
+level of lazyness/eagerness in each operation is external to each lazy
+object, the runtime, depending on which operation is being performed
+is going to assume the level of lazyness and perform the needed
+operations to apply that level.
+
+=head2 The lazyness level of some common operations
+
+=over
+
+=item List Assignment: my @a = @something;
+
+In order to provide p5-like behavior in list assignment, this
+operation is performed in the Mostly Eager level, meaning that if you do
+
+  my @a = grep { ... }, @b;
+
+the grep will be evaluated as long as @b is not infinite.
+
+  my @a = grep { ... }, 1, 2, 3, 4..*
+
+will give grep an infinite list (even if the first elements are
+known), therefore it will also be lazy. On the other hand
+
+  my @a = grep { ... }, 1, 2, 3, 4;
+
+will be eagerly evaluated. 
+
+=item Feed operators: my @a <== @something;
+
+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
+
+is completely lazy, even if 1,2,3 is a fairly small known compact
+list.
+
+=back
+
+But it's important to notice that eagerness takes precedence over
+lazyness, meaning that
+
+  my @a = grep { ... } <== map { ... } <== grep { ... }, 1, 2, 3
+
+Will be eagerly evaluated, but that is still different from
+
+  my @d = 1,2,3;
+  my @c = grep { ... }, @d;
+  my @b = map { ... }, @c;
+  my @a = grep { ... }, @b;
+
+Because in the first, the processing would be made as a flow, avoiding
+the creation of the intermediary eager lists that the second example
+creates. On the other hand
+
+  my @d <== 1,2,3;
+  my @c <== grep { ... }, @d;
+  my @b <== map { ... }, @c;
+  my @a = grep { ... }, @b;
+
+provides the same lazyness level of the first example.
+
+=head1 The Iterator Role
+
+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.
+
+When an iterator runs out of items, it will throw an exception.  
+
+The iterator role has the following methods:
+
+=head2 method prefix:<=> {...}
+
+Returns something appropriate depending on the context:
+
+=head2 method new(Laziness => $laziness, Context => $context) {...}
+
+Creates the iterator, with appropriate laziness defaults.  
+
+=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
+
+This is what is returned by default when an iterator is asked for, but no 
iterator type is known.  
+
+=head2 MapIterator implementation
+
+Example call:
+
+# this is a good example of loose context information anyway...
+   other_something(| map { ... }, something())
+
+When the map is initiated(???) this does the following steps in order:
+
+=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
+a general laundry list, please separate messages by topic.

Reply via email to