develooper Front page | perl.perl6.language | Postings from November 2002

Re: Continuations elified

Thread Previous | Thread Next
From:
Damian Conway
Date:
November 18, 2002 18:51
Subject:
Re: Continuations elified
Message ID:
3DD9A74C.205@conway.org
Larry wrote:

> So you can do it any of these ways:
> 
>     for <$dance> {
> 
>     for $dance.each {
> 
>     for each $dance: {
>                    ^ note colon
> 
> Then there's this approach to auto-iteration:
> 
>     my @dance := Iterator.new(@squares);
>     for @dance {

Okay, so now I need to make sense of the semantics of <...> and
C<for> and coroutines and their combined use.

Is the following correct?

==============================================================================

The presence of a C<yield> automatically makes a subroutine a coroutine:

	sub fibs {
		my ($a, $b) = (0, 1);
		loop {
			yield $b;
			($a, $b) = ($b, $a+$b);
		}
	}

Calling such a coroutine returns an Iterator object with (at least)
the following methods:

	next()			# resumes coroutine body until next C<yield>

	next(PARAM_LIST)	# resumes coroutine body until next C<yield>,
				# rebinding params to the args passed to C<next>.
				# PARAM_LIST is the same as the parameter list
				# of the coroutine that created the Iterator

	each()			# returns a lazy array, each element of which
				# is computed on demand by the appropriate
				# number of resumptions of the coroutine body


In a scalar context:

	<$fh>		# Calls $fh.readline (or maybe that's $fh.next???>
	<$iter>		# Calls $iter.next
	fibs()		# Returns iterator object
	<fibs()>	# Returns iterator object and calls that
			#    object's C<next> method (see note below)
	

In a list context:

	<$fh>		# Calls $fh.each
	<$iter>		# Calls $iter.each
	fibs()		# Returns iterator object
	<fibs()>	# Returns iterator object and calls object's C<each>


So then:

	for <$fh> {...}    # Build and then iterate a lazy array (the elements
			   # of which call back to the filehandle's input
			   # retrieval coroutine)

	for <$iter> {...}  # Build and then iterate a lazy array (the elements
			   # of which call back to the iterator's coroutine)

	for fibs() {...}   # Loop once, setting $_ to the iterator object
			   # that was returned by C<fibs>

	for <fibs()> {...} # Build and then iterate a lazy array (the elements
			   # of which call back to the coroutine of the
			   # iterator returned by C<fibs>


==============================================================================

Note: this all hangs together *very* nicely, except when someone writes:

	loop {
		my $nextfib = <fibs()>;
		...
	}

In which case $nextfib is perennially 1, since every call to C<fibs>
returns a new Iterator object.

The solution is very simple, of course:

		my $nextfib = <my $iter//=fibs()>;

but we might want to contemplate issuing a warning when someone calls
an argumentless coroutine within a scalar context <...>.

Damian


Thread Previous | Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About